Rename all of the modules
This is separate from the previous patch - it's just the results of running the script so we can review the two a little independently. We should probably squash them. Change-Id: I838f15cf4a32455a5be20033c8ddc27db6ca15c0
This commit is contained in:
parent
52905480b8
commit
e47c4671c7
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Authenticate to the cloud
|
- name: Authenticate to the cloud
|
||||||
openstack.cloud.os_auth:
|
openstack.cloud.auth:
|
||||||
cloud={{ cloud }}
|
cloud={{ cloud }}
|
||||||
|
|
||||||
- debug: var=service_catalog
|
- debug: var=service_catalog
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: List all profiles
|
- name: List all profiles
|
||||||
openstack.cloud.os_client_config:
|
openstack.cloud.config:
|
||||||
register: list
|
register: list
|
||||||
|
|
||||||
# WARNING: This will output sensitive authentication information!!!!
|
# WARNING: This will output sensitive authentication information!!!!
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
---
|
---
|
||||||
- name: Create group
|
- name: Create group
|
||||||
openstack.cloud.os_group:
|
openstack.cloud.identity_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ group_name }}"
|
name: "{{ group_name }}"
|
||||||
|
|
||||||
- name: Update group
|
- name: Update group
|
||||||
openstack.cloud.os_group:
|
openstack.cloud.identity_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ group_name }}"
|
name: "{{ group_name }}"
|
||||||
description: "updated description"
|
description: "updated description"
|
||||||
|
|
||||||
- name: Delete group
|
- name: Delete group
|
||||||
openstack.cloud.os_group:
|
openstack.cloud.identity_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ group_name }}"
|
name: "{{ group_name }}"
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
shell: truncate -s 1048576 {{ tmp_file.stdout }}
|
shell: truncate -s 1048576 {{ tmp_file.stdout }}
|
||||||
|
|
||||||
- name: Create raw image (defaults)
|
- name: Create raw image (defaults)
|
||||||
openstack.cloud.os_image:
|
openstack.cloud.image:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ image_name }}"
|
name: "{{ image_name }}"
|
||||||
@ -18,13 +18,13 @@
|
|||||||
- debug: var=image
|
- debug: var=image
|
||||||
|
|
||||||
- name: Delete raw image (defaults)
|
- name: Delete raw image (defaults)
|
||||||
openstack.cloud.os_image:
|
openstack.cloud.image:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ image_name }}"
|
name: "{{ image_name }}"
|
||||||
|
|
||||||
- name: Create raw image (complex)
|
- name: Create raw image (complex)
|
||||||
openstack.cloud.os_image:
|
openstack.cloud.image:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ image_name }}"
|
name: "{{ image_name }}"
|
||||||
@ -43,7 +43,7 @@
|
|||||||
- debug: var=image
|
- debug: var=image
|
||||||
|
|
||||||
- name: Delete raw image (complex)
|
- name: Delete raw image (complex)
|
||||||
openstack.cloud.os_image:
|
openstack.cloud.image:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ image_name }}"
|
name: "{{ image_name }}"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create keypair (non-existing)
|
- name: Create keypair (non-existing)
|
||||||
openstack.cloud.os_keypair:
|
openstack.cloud.keypair:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ keypair_name }}"
|
name: "{{ keypair_name }}"
|
||||||
state: present
|
state: present
|
||||||
@ -14,7 +14,7 @@
|
|||||||
- keypair.key.public_key is defined and keypair.key.public_key
|
- keypair.key.public_key is defined and keypair.key.public_key
|
||||||
|
|
||||||
- name: Delete keypair (non-existing)
|
- name: Delete keypair (non-existing)
|
||||||
openstack.cloud.os_keypair:
|
openstack.cloud.keypair:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ keypair_name }}"
|
name: "{{ keypair_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
@ -26,27 +26,27 @@
|
|||||||
ssh_key_file: .ssh/shade_id_rsa
|
ssh_key_file: .ssh/shade_id_rsa
|
||||||
|
|
||||||
- name: Create keypair (file)
|
- name: Create keypair (file)
|
||||||
openstack.cloud.os_keypair:
|
openstack.cloud.keypair:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ keypair_name }}"
|
name: "{{ keypair_name }}"
|
||||||
state: present
|
state: present
|
||||||
public_key_file: "{{ ansible_env.HOME }}/.ssh/shade_id_rsa.pub"
|
public_key_file: "{{ ansible_env.HOME }}/.ssh/shade_id_rsa.pub"
|
||||||
|
|
||||||
- name: Delete keypair (file)
|
- name: Delete keypair (file)
|
||||||
openstack.cloud.os_keypair:
|
openstack.cloud.keypair:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ keypair_name }}"
|
name: "{{ keypair_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: Create keypair (key)
|
- name: Create keypair (key)
|
||||||
openstack.cloud.os_keypair:
|
openstack.cloud.keypair:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ keypair_name }}"
|
name: "{{ keypair_name }}"
|
||||||
state: present
|
state: present
|
||||||
public_key: "{{ lookup('file', '~/.ssh/shade_id_rsa.pub') }}"
|
public_key: "{{ lookup('file', '~/.ssh/shade_id_rsa.pub') }}"
|
||||||
|
|
||||||
- name: Delete keypair (key)
|
- name: Delete keypair (key)
|
||||||
openstack.cloud.os_keypair:
|
openstack.cloud.keypair:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ keypair_name }}"
|
name: "{{ keypair_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
---
|
---
|
||||||
- name: Create keystone domain
|
- name: Create keystone domain
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ domain_name }}"
|
name: "{{ domain_name }}"
|
||||||
description: "test description"
|
description: "test description"
|
||||||
|
|
||||||
- name: Update keystone domain
|
- name: Update keystone domain
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ domain_name }}"
|
name: "{{ domain_name }}"
|
||||||
description: "updated description"
|
description: "updated description"
|
||||||
|
|
||||||
- name: Delete keystone domain
|
- name: Delete keystone domain
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ domain_name }}"
|
name: "{{ domain_name }}"
|
||||||
|
@ -9,23 +9,23 @@
|
|||||||
# meta/action_groups.yml glue seems to be missing
|
# meta/action_groups.yml glue seems to be missing
|
||||||
# group/os:
|
# group/os:
|
||||||
# cloud: "{{ cloud }}"
|
# cloud: "{{ cloud }}"
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
idp_id: "{{ idp_name }}"
|
idp_id: "{{ idp_name }}"
|
||||||
openstack.cloud.os_keystone_federation_protocol_info:
|
openstack.cloud.keystone_federation_protocol_info:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
idp_id: "{{ idp_name }}"
|
idp_id: "{{ idp_name }}"
|
||||||
block:
|
block:
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
# Initial setup
|
# Initial setup
|
||||||
- name: 'Create test Domain'
|
- name: 'Create test Domain'
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
name: '{{ domain_name }}'
|
name: '{{ domain_name }}'
|
||||||
register: create_domain
|
register: create_domain
|
||||||
- assert:
|
- assert:
|
||||||
@ -37,7 +37,7 @@
|
|||||||
domain_id: '{{ create_domain.id }}'
|
domain_id: '{{ create_domain.id }}'
|
||||||
|
|
||||||
- name: 'Create test Identity Provider'
|
- name: 'Create test Identity Provider'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
domain_id: '{{ domain_id }}'
|
domain_id: '{{ domain_id }}'
|
||||||
@ -47,7 +47,7 @@
|
|||||||
- create_idp is successful
|
- create_idp is successful
|
||||||
|
|
||||||
- name: 'Create test mapping (1)'
|
- name: 'Create test mapping (1)'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name_1 }}'
|
name: '{{ mapping_name_1 }}'
|
||||||
rules: '{{ mapping_rules_1 }}'
|
rules: '{{ mapping_rules_1 }}'
|
||||||
@ -56,7 +56,7 @@
|
|||||||
that:
|
that:
|
||||||
- create_mapping is successful
|
- create_mapping is successful
|
||||||
- name: 'Create test mapping (2)'
|
- name: 'Create test mapping (2)'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name_2 }}'
|
name: '{{ mapping_name_2 }}'
|
||||||
rules: '{{ mapping_rules_2 }}'
|
rules: '{{ mapping_rules_2 }}'
|
||||||
@ -68,7 +68,7 @@
|
|||||||
# We *should* have a blank slate to start with, but we also shouldn't
|
# We *should* have a blank slate to start with, but we also shouldn't
|
||||||
# explode if I(state=absent) and the IDP doesn't exist
|
# explode if I(state=absent) and the IDP doesn't exist
|
||||||
- name: "Ensure Protocol doesn't exist to start"
|
- name: "Ensure Protocol doesn't exist to start"
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
register: delete_protocol
|
register: delete_protocol
|
||||||
@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
- name: 'Create protocol - CHECK MODE'
|
- name: 'Create protocol - CHECK MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
mapping_id: '{{ mapping_name_1 }}'
|
mapping_id: '{{ mapping_name_1 }}'
|
||||||
@ -92,7 +92,7 @@
|
|||||||
- create_protocol is changed
|
- create_protocol is changed
|
||||||
|
|
||||||
- name: 'Fetch Protocol info (should be absent)'
|
- name: 'Fetch Protocol info (should be absent)'
|
||||||
openstack.cloud.os_keystone_federation_protocol_info:
|
openstack.cloud.keystone_federation_protocol_info:
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
register: protocol_info
|
register: protocol_info
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
@ -101,7 +101,7 @@
|
|||||||
- protocol_info is failed
|
- protocol_info is failed
|
||||||
|
|
||||||
- name: 'Create protocol'
|
- name: 'Create protocol'
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
mapping_id: '{{ mapping_name_1 }}'
|
mapping_id: '{{ mapping_name_1 }}'
|
||||||
@ -124,7 +124,7 @@
|
|||||||
|
|
||||||
- name: 'Create protocol (retry - no change) - CHECK MODE'
|
- name: 'Create protocol (retry - no change) - CHECK MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
mapping_id: '{{ mapping_name_1 }}'
|
mapping_id: '{{ mapping_name_1 }}'
|
||||||
@ -135,7 +135,7 @@
|
|||||||
- create_protocol is not changed
|
- create_protocol is not changed
|
||||||
|
|
||||||
- name: 'Create protocol (retry - no change)'
|
- name: 'Create protocol (retry - no change)'
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
mapping_id: '{{ mapping_name_1 }}'
|
mapping_id: '{{ mapping_name_1 }}'
|
||||||
@ -161,7 +161,7 @@
|
|||||||
|
|
||||||
- name: 'Update protocol - CHECK MODE'
|
- name: 'Update protocol - CHECK MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
mapping_id: '{{ mapping_name_2 }}'
|
mapping_id: '{{ mapping_name_2 }}'
|
||||||
@ -172,7 +172,7 @@
|
|||||||
- update_protocol is changed
|
- update_protocol is changed
|
||||||
|
|
||||||
- name: 'Update protocol'
|
- name: 'Update protocol'
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
mapping_id: '{{ mapping_name_2 }}'
|
mapping_id: '{{ mapping_name_2 }}'
|
||||||
@ -195,7 +195,7 @@
|
|||||||
|
|
||||||
- name: 'Update protocol (retry - no change) - CHECK MODE'
|
- name: 'Update protocol (retry - no change) - CHECK MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
mapping_id: '{{ mapping_name_2 }}'
|
mapping_id: '{{ mapping_name_2 }}'
|
||||||
@ -206,7 +206,7 @@
|
|||||||
- update_protocol is not changed
|
- update_protocol is not changed
|
||||||
|
|
||||||
- name: 'Update protocol (retry - no change)'
|
- name: 'Update protocol (retry - no change)'
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
mapping_id: '{{ mapping_name_2 }}'
|
mapping_id: '{{ mapping_name_2 }}'
|
||||||
@ -228,10 +228,10 @@
|
|||||||
protocol: '{{ update_protocol.protocol }}'
|
protocol: '{{ update_protocol.protocol }}'
|
||||||
|
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
# Create second protocol to test os_keystone_federation_protocol_info
|
# Create second protocol to test openstack.cloud.keystone_federation_protocol_info
|
||||||
|
|
||||||
- name: 'Create protocol (2)'
|
- name: 'Create protocol (2)'
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ protocol_name_2 }}'
|
name: '{{ protocol_name_2 }}'
|
||||||
mapping_id: '{{ mapping_name_1 }}'
|
mapping_id: '{{ mapping_name_1 }}'
|
||||||
@ -253,10 +253,10 @@
|
|||||||
protocol: '{{ create_protocol_2.protocol }}'
|
protocol: '{{ create_protocol_2.protocol }}'
|
||||||
|
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
# Basic tests of os_keystone_federation_protocol_info
|
# Basic tests of openstack.cloud.keystone_federation_protocol_info
|
||||||
|
|
||||||
- name: 'Fetch Protocol info (a specific protocol)'
|
- name: 'Fetch Protocol info (a specific protocol)'
|
||||||
openstack.cloud.os_keystone_federation_protocol_info:
|
openstack.cloud.keystone_federation_protocol_info:
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
register: protocol_info
|
register: protocol_info
|
||||||
- assert:
|
- assert:
|
||||||
@ -276,7 +276,7 @@
|
|||||||
protocol: '{{ protocol_info.protocols[0] }}'
|
protocol: '{{ protocol_info.protocols[0] }}'
|
||||||
|
|
||||||
- name: 'Fetch Protocol info (all protocols on our test IDP)'
|
- name: 'Fetch Protocol info (all protocols on our test IDP)'
|
||||||
openstack.cloud.os_keystone_federation_protocol_info: {}
|
openstack.cloud.keystone_federation_protocol_info: {}
|
||||||
# idp_id defined in defaults at the start
|
# idp_id defined in defaults at the start
|
||||||
register: protocol_info
|
register: protocol_info
|
||||||
- assert:
|
- assert:
|
||||||
@ -311,7 +311,7 @@
|
|||||||
|
|
||||||
- name: 'Delete protocol - CHECK MODE'
|
- name: 'Delete protocol - CHECK MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
register: update_protocol
|
register: update_protocol
|
||||||
@ -321,7 +321,7 @@
|
|||||||
- update_protocol is changed
|
- update_protocol is changed
|
||||||
|
|
||||||
- name: 'Delete protocol'
|
- name: 'Delete protocol'
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
register: update_protocol
|
register: update_protocol
|
||||||
@ -332,7 +332,7 @@
|
|||||||
|
|
||||||
- name: 'Delete protocol (retry - no change) - CHECK MODE'
|
- name: 'Delete protocol (retry - no change) - CHECK MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
register: update_protocol
|
register: update_protocol
|
||||||
@ -342,7 +342,7 @@
|
|||||||
- update_protocol is not changed
|
- update_protocol is not changed
|
||||||
|
|
||||||
- name: 'Delete protocol (retry - no change)'
|
- name: 'Delete protocol (retry - no change)'
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
register: update_protocol
|
register: update_protocol
|
||||||
@ -355,39 +355,39 @@
|
|||||||
# Clean up after ourselves
|
# Clean up after ourselves
|
||||||
always:
|
always:
|
||||||
- name: 'Delete protocol'
|
- name: 'Delete protocol'
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ protocol_name }}'
|
name: '{{ protocol_name }}'
|
||||||
idp_id: '{{ idp_name }}'
|
idp_id: '{{ idp_name }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: 'Delete protocol (2)'
|
- name: 'Delete protocol (2)'
|
||||||
openstack.cloud.os_keystone_federation_protocol:
|
openstack.cloud.keystone_federation_protocol:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ protocol_name_2 }}'
|
name: '{{ protocol_name_2 }}'
|
||||||
idp_id: '{{ idp_name }}'
|
idp_id: '{{ idp_name }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: 'Delete mapping 1'
|
- name: 'Delete mapping 1'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name_1 }}'
|
name: '{{ mapping_name_1 }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: 'Delete mapping 2'
|
- name: 'Delete mapping 2'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name_2 }}'
|
name: '{{ mapping_name_2 }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: 'Delete idp'
|
- name: 'Delete idp'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: 'Delete domain'
|
- name: 'Delete domain'
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ domain_name }}'
|
name: '{{ domain_name }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
@ -9,17 +9,17 @@
|
|||||||
# meta/action_groups.yml glue seems to be missing
|
# meta/action_groups.yml glue seems to be missing
|
||||||
# group/os:
|
# group/os:
|
||||||
# cloud: "{{ cloud }}"
|
# cloud: "{{ cloud }}"
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
openstack.cloud.os_keystone_identity_provider_info:
|
openstack.cloud.federation_idp_info:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
block:
|
block:
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
# Initial setup
|
# Initial setup
|
||||||
- name: 'Create test domain'
|
- name: 'Create test domain'
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
name: '{{ domain_name }}'
|
name: '{{ domain_name }}'
|
||||||
register: create_domain
|
register: create_domain
|
||||||
- assert:
|
- assert:
|
||||||
@ -33,7 +33,7 @@
|
|||||||
# We *should* have a blank slate to start with, but we also shouldn't
|
# We *should* have a blank slate to start with, but we also shouldn't
|
||||||
# explode if I(state=absent) and the IDP doesn't exist
|
# explode if I(state=absent) and the IDP doesn't exist
|
||||||
- name: "Ensure IDP doesn't exist to start"
|
- name: "Ensure IDP doesn't exist to start"
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: delete_idp
|
register: delete_idp
|
||||||
@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
- name: 'Create IDP - CHECK_MODE'
|
- name: 'Create IDP - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
domain_id: '{{ domain_id }}'
|
domain_id: '{{ domain_id }}'
|
||||||
@ -57,7 +57,7 @@
|
|||||||
- create_idp is changed
|
- create_idp is changed
|
||||||
|
|
||||||
- name: 'Fetch identity_provider info (provider should be absent)'
|
- name: 'Fetch identity_provider info (provider should be absent)'
|
||||||
openstack.cloud.os_keystone_identity_provider_info:
|
openstack.cloud.federation_idp_info:
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: identity_provider_info
|
register: identity_provider_info
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
@ -66,7 +66,7 @@
|
|||||||
- identity_provider_info is failed
|
- identity_provider_info is failed
|
||||||
|
|
||||||
- name: 'Create IDP'
|
- name: 'Create IDP'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
domain_id: '{{ domain_id }}'
|
domain_id: '{{ domain_id }}'
|
||||||
@ -94,7 +94,7 @@
|
|||||||
idp: '{{ create_identity_provider.identity_provider }}'
|
idp: '{{ create_identity_provider.identity_provider }}'
|
||||||
|
|
||||||
- name: 'Fetch IDP info - with name'
|
- name: 'Fetch IDP info - with name'
|
||||||
openstack.cloud.os_keystone_identity_provider_info:
|
openstack.cloud.federation_idp_info:
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: identity_provider_info
|
register: identity_provider_info
|
||||||
- assert:
|
- assert:
|
||||||
@ -121,7 +121,7 @@
|
|||||||
idp: '{{ identity_provider_info.identity_providers[0] }}'
|
idp: '{{ identity_provider_info.identity_providers[0] }}'
|
||||||
|
|
||||||
- name: 'Fetch identity_provider info - without name'
|
- name: 'Fetch identity_provider info - without name'
|
||||||
openstack.cloud.os_keystone_identity_provider_info: {}
|
openstack.cloud.federation_idp_info: {}
|
||||||
register: identity_provider_info
|
register: identity_provider_info
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
@ -143,7 +143,7 @@
|
|||||||
|
|
||||||
- name: 'Create identity_provider (retry - no change) - CHECK_MODE'
|
- name: 'Create identity_provider (retry - no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
domain_id: '{{ domain_id }}'
|
domain_id: '{{ domain_id }}'
|
||||||
@ -154,7 +154,7 @@
|
|||||||
- create_identity_provider is not changed
|
- create_identity_provider is not changed
|
||||||
|
|
||||||
- name: 'Create identity_provider (retry - no change)'
|
- name: 'Create identity_provider (retry - no change)'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
domain_id: '{{ domain_id }}'
|
domain_id: '{{ domain_id }}'
|
||||||
@ -186,7 +186,7 @@
|
|||||||
|
|
||||||
- name: 'Update IDP set description - CHECK_MODE'
|
- name: 'Update IDP set description - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
description: '{{ idp_description }}'
|
description: '{{ idp_description }}'
|
||||||
@ -197,7 +197,7 @@
|
|||||||
- update_identity_provider is changed
|
- update_identity_provider is changed
|
||||||
|
|
||||||
- name: 'Update IDP set description'
|
- name: 'Update IDP set description'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
description: '{{ idp_description }}'
|
description: '{{ idp_description }}'
|
||||||
@ -226,7 +226,7 @@
|
|||||||
|
|
||||||
- name: 'Update IDP set description (retry - no change) - CHECK_MODE'
|
- name: 'Update IDP set description (retry - no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
description: '{{ idp_description }}'
|
description: '{{ idp_description }}'
|
||||||
@ -237,7 +237,7 @@
|
|||||||
- update_identity_provider is not changed
|
- update_identity_provider is not changed
|
||||||
|
|
||||||
- name: 'Update IDP set description (retry - no change)'
|
- name: 'Update IDP set description (retry - no change)'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
description: '{{ idp_description }}'
|
description: '{{ idp_description }}'
|
||||||
@ -267,7 +267,7 @@
|
|||||||
|
|
||||||
- name: 'Update IDP set Remote IDs - CHECK_MODE'
|
- name: 'Update IDP set Remote IDs - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
remote_ids: '{{ remote_ids_1 }}'
|
remote_ids: '{{ remote_ids_1 }}'
|
||||||
@ -278,7 +278,7 @@
|
|||||||
- update_identity_provider is changed
|
- update_identity_provider is changed
|
||||||
|
|
||||||
- name: 'Update IDP set Remote IDs'
|
- name: 'Update IDP set Remote IDs'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
remote_ids: '{{ remote_ids_1 }}'
|
remote_ids: '{{ remote_ids_1 }}'
|
||||||
@ -307,7 +307,7 @@
|
|||||||
|
|
||||||
- name: 'Update IDP set Remote IDs (retry - no change) - CHECK_MODE'
|
- name: 'Update IDP set Remote IDs (retry - no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
remote_ids: '{{ remote_ids_1 }}'
|
remote_ids: '{{ remote_ids_1 }}'
|
||||||
@ -318,7 +318,7 @@
|
|||||||
- update_identity_provider is not changed
|
- update_identity_provider is not changed
|
||||||
|
|
||||||
- name: 'Update IDP set Remote IDs (retry - no change)'
|
- name: 'Update IDP set Remote IDs (retry - no change)'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
remote_ids: '{{ remote_ids_1 }}'
|
remote_ids: '{{ remote_ids_1 }}'
|
||||||
@ -348,7 +348,7 @@
|
|||||||
|
|
||||||
- name: 'Update IDP set Disabled - CHECK_MODE'
|
- name: 'Update IDP set Disabled - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
enabled: False
|
enabled: False
|
||||||
@ -359,7 +359,7 @@
|
|||||||
- update_identity_provider is changed
|
- update_identity_provider is changed
|
||||||
|
|
||||||
- name: 'Update IDP set Disabled'
|
- name: 'Update IDP set Disabled'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
enabled: False
|
enabled: False
|
||||||
@ -388,7 +388,7 @@
|
|||||||
|
|
||||||
- name: 'Update IDP set Disabled (retry - no change) - CHECK_MODE'
|
- name: 'Update IDP set Disabled (retry - no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
enabled: False
|
enabled: False
|
||||||
@ -399,7 +399,7 @@
|
|||||||
- update_identity_provider is not changed
|
- update_identity_provider is not changed
|
||||||
|
|
||||||
- name: 'Update IDP set Disabled (retry - no change)'
|
- name: 'Update IDP set Disabled (retry - no change)'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
enabled: False
|
enabled: False
|
||||||
@ -429,7 +429,7 @@
|
|||||||
# If we don't specify anything to change, then nothing should change...
|
# If we don't specify anything to change, then nothing should change...
|
||||||
- name: 'Minimal call to IDP (no change) - CHECK_MODE'
|
- name: 'Minimal call to IDP (no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: update_identity_provider
|
register: update_identity_provider
|
||||||
@ -439,7 +439,7 @@
|
|||||||
- update_identity_provider is not changed
|
- update_identity_provider is not changed
|
||||||
|
|
||||||
- name: 'Minimal call to IDP (no change)'
|
- name: 'Minimal call to IDP (no change)'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: update_identity_provider
|
register: update_identity_provider
|
||||||
@ -470,7 +470,7 @@
|
|||||||
|
|
||||||
- name: 'Update all updatable IDP parameters - CHECK_MODE'
|
- name: 'Update all updatable IDP parameters - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
description: '{{ idp_description_2 }}'
|
description: '{{ idp_description_2 }}'
|
||||||
@ -483,7 +483,7 @@
|
|||||||
- update_identity_provider is changed
|
- update_identity_provider is changed
|
||||||
|
|
||||||
- name: 'Update all updatable IDP parameters'
|
- name: 'Update all updatable IDP parameters'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
description: '{{ idp_description_2 }}'
|
description: '{{ idp_description_2 }}'
|
||||||
@ -514,7 +514,7 @@
|
|||||||
|
|
||||||
- name: 'Update all updatable IDP parameters (no change) - CHECK_MODE'
|
- name: 'Update all updatable IDP parameters (no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
description: '{{ idp_description_2 }}'
|
description: '{{ idp_description_2 }}'
|
||||||
@ -527,7 +527,7 @@
|
|||||||
- update_identity_provider is not changed
|
- update_identity_provider is not changed
|
||||||
|
|
||||||
- name: 'Update all updatable IDP parameters (no change)'
|
- name: 'Update all updatable IDP parameters (no change)'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
description: '{{ idp_description_2 }}'
|
description: '{{ idp_description_2 }}'
|
||||||
@ -561,7 +561,7 @@
|
|||||||
|
|
||||||
- name: 'Create complex IDP - CHECK_MODE'
|
- name: 'Create complex IDP - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name_2 }}'
|
name: '{{ idp_name_2 }}'
|
||||||
domain_id: '{{ domain_id }}'
|
domain_id: '{{ domain_id }}'
|
||||||
@ -575,7 +575,7 @@
|
|||||||
- create_identity_provider is changed
|
- create_identity_provider is changed
|
||||||
|
|
||||||
- name: 'Create complex IDP'
|
- name: 'Create complex IDP'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name_2 }}'
|
name: '{{ idp_name_2 }}'
|
||||||
domain_id: '{{ domain_id }}'
|
domain_id: '{{ domain_id }}'
|
||||||
@ -607,7 +607,7 @@
|
|||||||
|
|
||||||
- name: 'Create complex IDP (retry - no change) - CHECK_MODE'
|
- name: 'Create complex IDP (retry - no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name_2 }}'
|
name: '{{ idp_name_2 }}'
|
||||||
domain_id: '{{ domain_id }}'
|
domain_id: '{{ domain_id }}'
|
||||||
@ -621,7 +621,7 @@
|
|||||||
- create_identity_provider is not changed
|
- create_identity_provider is not changed
|
||||||
|
|
||||||
- name: 'Create complex IDP'
|
- name: 'Create complex IDP'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ idp_name_2 }}'
|
name: '{{ idp_name_2 }}'
|
||||||
domain_id: '{{ domain_id }}'
|
domain_id: '{{ domain_id }}'
|
||||||
@ -653,7 +653,7 @@
|
|||||||
|
|
||||||
# Attempt to ensure that if we search we only get the one we expect
|
# Attempt to ensure that if we search we only get the one we expect
|
||||||
- name: 'Fetch Complex IDP info - with name'
|
- name: 'Fetch Complex IDP info - with name'
|
||||||
openstack.cloud.os_keystone_identity_provider_info:
|
openstack.cloud.federation_idp_info:
|
||||||
name: '{{ idp_name_2 }}'
|
name: '{{ idp_name_2 }}'
|
||||||
register: identity_provider_info
|
register: identity_provider_info
|
||||||
- assert:
|
- assert:
|
||||||
@ -680,7 +680,7 @@
|
|||||||
|
|
||||||
# Ensure that if we do search we get both of the results we expect
|
# Ensure that if we do search we get both of the results we expect
|
||||||
- name: 'Fetch multiple IDP info - without name'
|
- name: 'Fetch multiple IDP info - without name'
|
||||||
openstack.cloud.os_keystone_identity_provider_info: {}
|
openstack.cloud.federation_idp_info: {}
|
||||||
register: identity_provider_info
|
register: identity_provider_info
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
@ -722,7 +722,7 @@
|
|||||||
|
|
||||||
- name: 'Delete identity_provider - CHECK_MODE'
|
- name: 'Delete identity_provider - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: delete_identity_provider
|
register: delete_identity_provider
|
||||||
@ -732,7 +732,7 @@
|
|||||||
- delete_identity_provider is changed
|
- delete_identity_provider is changed
|
||||||
|
|
||||||
- name: 'Delete identity_provider'
|
- name: 'Delete identity_provider'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: delete_identity_provider
|
register: delete_identity_provider
|
||||||
@ -743,7 +743,7 @@
|
|||||||
|
|
||||||
- name: 'Delete identity_provider (retry - no change) - CHECK_MODE'
|
- name: 'Delete identity_provider (retry - no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: delete_identity_provider
|
register: delete_identity_provider
|
||||||
@ -753,7 +753,7 @@
|
|||||||
- delete_identity_provider is not changed
|
- delete_identity_provider is not changed
|
||||||
|
|
||||||
- name: 'Delete identity_provider (retry - no change) '
|
- name: 'Delete identity_provider (retry - no change) '
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: delete_identity_provider
|
register: delete_identity_provider
|
||||||
@ -763,7 +763,7 @@
|
|||||||
- delete_identity_provider is not changed
|
- delete_identity_provider is not changed
|
||||||
|
|
||||||
- name: 'Fetch identity_provider info after deletion'
|
- name: 'Fetch identity_provider info after deletion'
|
||||||
openstack.cloud.os_keystone_identity_provider_info:
|
openstack.cloud.federation_idp_info:
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
register: identity_provider_info
|
register: identity_provider_info
|
||||||
ignore_errors: True
|
ignore_errors: True
|
||||||
@ -772,7 +772,7 @@
|
|||||||
- identity_provider_info is failed
|
- identity_provider_info is failed
|
||||||
|
|
||||||
- name: 'Delete second identity_provider'
|
- name: 'Delete second identity_provider'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ idp_name_2 }}'
|
name: '{{ idp_name_2 }}'
|
||||||
register: delete_identity_provider
|
register: delete_identity_provider
|
||||||
@ -783,19 +783,19 @@
|
|||||||
|
|
||||||
always:
|
always:
|
||||||
- name: 'Delete idp'
|
- name: 'Delete idp'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ idp_name }}'
|
name: '{{ idp_name }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: 'Delete second identity_provider'
|
- name: 'Delete second identity_provider'
|
||||||
openstack.cloud.os_keystone_identity_provider:
|
openstack.cloud.federation_idp:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ idp_name_2 }}'
|
name: '{{ idp_name_2 }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: 'Delete domain'
|
- name: 'Delete domain'
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ domain_name }}'
|
name: '{{ domain_name }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
# meta/action_groups.yml glue seems to be missing
|
# meta/action_groups.yml glue seems to be missing
|
||||||
# group/os:
|
# group/os:
|
||||||
# cloud: "{{ cloud }}"
|
# cloud: "{{ cloud }}"
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
openstack.cloud.os_keystone_mapping_info:
|
openstack.cloud.federation_mapping_info:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
block:
|
block:
|
||||||
- name: "Ensure mapping doesn't exist to start"
|
- name: "Ensure mapping doesn't exist to start"
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
register: delete_mapping
|
register: delete_mapping
|
||||||
@ -18,7 +18,7 @@
|
|||||||
- delete_mapping is successful
|
- delete_mapping is successful
|
||||||
|
|
||||||
- name: 'Create mapping - CHECK_MODE'
|
- name: 'Create mapping - CHECK_MODE'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
rules: '{{ mapping_rules_1 }}'
|
rules: '{{ mapping_rules_1 }}'
|
||||||
@ -30,7 +30,7 @@
|
|||||||
- create_mapping is changed
|
- create_mapping is changed
|
||||||
|
|
||||||
- name: 'Fetch mapping info (mapping should be absent)'
|
- name: 'Fetch mapping info (mapping should be absent)'
|
||||||
openstack.cloud.os_keystone_mapping_info:
|
openstack.cloud.federation_mapping_info:
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
register: mapping_info
|
register: mapping_info
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
@ -39,7 +39,7 @@
|
|||||||
- mapping_info is failed
|
- mapping_info is failed
|
||||||
|
|
||||||
- name: 'Create mapping'
|
- name: 'Create mapping'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
rules: '{{ mapping_rules_1 }}'
|
rules: '{{ mapping_rules_1 }}'
|
||||||
@ -56,7 +56,7 @@
|
|||||||
- create_mapping.mapping.rules | length == 1
|
- create_mapping.mapping.rules | length == 1
|
||||||
|
|
||||||
- name: 'Fetch mapping info - with name'
|
- name: 'Fetch mapping info - with name'
|
||||||
openstack.cloud.os_keystone_mapping_info:
|
openstack.cloud.federation_mapping_info:
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
register: mapping_info
|
register: mapping_info
|
||||||
- assert:
|
- assert:
|
||||||
@ -74,7 +74,7 @@
|
|||||||
mapping_0: '{{ mapping_info.mappings[0] }}'
|
mapping_0: '{{ mapping_info.mappings[0] }}'
|
||||||
|
|
||||||
- name: 'Fetch mapping info - without name'
|
- name: 'Fetch mapping info - without name'
|
||||||
openstack.cloud.os_keystone_mapping_info: {}
|
openstack.cloud.federation_mapping_info: {}
|
||||||
register: mapping_info
|
register: mapping_info
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
@ -92,7 +92,7 @@
|
|||||||
mapping_0: '{{ mapping_info.mappings[0] }}'
|
mapping_0: '{{ mapping_info.mappings[0] }}'
|
||||||
|
|
||||||
- name: 'Create mapping (retry - no change) - CHECK_MODE'
|
- name: 'Create mapping (retry - no change) - CHECK_MODE'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
rules: '{{ mapping_rules_1 }}'
|
rules: '{{ mapping_rules_1 }}'
|
||||||
@ -104,7 +104,7 @@
|
|||||||
- create_mapping is not changed
|
- create_mapping is not changed
|
||||||
|
|
||||||
- name: 'Create mapping (retry - no change)'
|
- name: 'Create mapping (retry - no change)'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
rules: '{{ mapping_rules_1 }}'
|
rules: '{{ mapping_rules_1 }}'
|
||||||
@ -121,7 +121,7 @@
|
|||||||
- create_mapping.mapping.rules | length == 1
|
- create_mapping.mapping.rules | length == 1
|
||||||
|
|
||||||
- name: 'Update mapping - CHECK_MODE'
|
- name: 'Update mapping - CHECK_MODE'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
rules: '{{ mapping_rules_2 }}'
|
rules: '{{ mapping_rules_2 }}'
|
||||||
@ -133,7 +133,7 @@
|
|||||||
- update_mapping is changed
|
- update_mapping is changed
|
||||||
|
|
||||||
- name: 'Update mapping'
|
- name: 'Update mapping'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
rules: '{{ mapping_rules_2 }}'
|
rules: '{{ mapping_rules_2 }}'
|
||||||
@ -150,7 +150,7 @@
|
|||||||
- update_mapping.mapping.rules | length == 1
|
- update_mapping.mapping.rules | length == 1
|
||||||
|
|
||||||
- name: 'Update mapping (retry - no change)'
|
- name: 'Update mapping (retry - no change)'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
rules: '{{ mapping_rules_2 }}'
|
rules: '{{ mapping_rules_2 }}'
|
||||||
@ -167,7 +167,7 @@
|
|||||||
- update_mapping.mapping.rules | length == 1
|
- update_mapping.mapping.rules | length == 1
|
||||||
|
|
||||||
- name: 'Create second mapping'
|
- name: 'Create second mapping'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'present'
|
state: 'present'
|
||||||
name: '{{ mapping_name_2 }}'
|
name: '{{ mapping_name_2 }}'
|
||||||
rules: '{{ mapping_rules_1 }}'
|
rules: '{{ mapping_rules_1 }}'
|
||||||
@ -184,7 +184,7 @@
|
|||||||
- create_mapping.mapping.rules | length == 1
|
- create_mapping.mapping.rules | length == 1
|
||||||
|
|
||||||
- name: 'Fetch mapping (2) info - with name'
|
- name: 'Fetch mapping (2) info - with name'
|
||||||
openstack.cloud.os_keystone_mapping_info:
|
openstack.cloud.federation_mapping_info:
|
||||||
name: '{{ mapping_name_2 }}'
|
name: '{{ mapping_name_2 }}'
|
||||||
register: mapping_info
|
register: mapping_info
|
||||||
- assert:
|
- assert:
|
||||||
@ -202,7 +202,7 @@
|
|||||||
mapping_0: '{{ mapping_info.mappings[0] }}'
|
mapping_0: '{{ mapping_info.mappings[0] }}'
|
||||||
|
|
||||||
- name: 'Fetch mapping info - without name'
|
- name: 'Fetch mapping info - without name'
|
||||||
openstack.cloud.os_keystone_mapping_info: {}
|
openstack.cloud.federation_mapping_info: {}
|
||||||
register: mapping_info
|
register: mapping_info
|
||||||
- assert:
|
- assert:
|
||||||
that:
|
that:
|
||||||
@ -226,7 +226,7 @@
|
|||||||
mapping_1: '{{ mapping_info.mappings[1] }}'
|
mapping_1: '{{ mapping_info.mappings[1] }}'
|
||||||
|
|
||||||
- name: 'Delete mapping - CHECK_MODE'
|
- name: 'Delete mapping - CHECK_MODE'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
register: delete_mapping
|
register: delete_mapping
|
||||||
@ -237,7 +237,7 @@
|
|||||||
- delete_mapping is changed
|
- delete_mapping is changed
|
||||||
|
|
||||||
- name: 'Delete mapping'
|
- name: 'Delete mapping'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
register: delete_mapping
|
register: delete_mapping
|
||||||
@ -247,7 +247,7 @@
|
|||||||
- delete_mapping is changed
|
- delete_mapping is changed
|
||||||
|
|
||||||
- name: 'Delete mapping (retry - no change) - CHECK_MODE'
|
- name: 'Delete mapping (retry - no change) - CHECK_MODE'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
register: delete_mapping
|
register: delete_mapping
|
||||||
@ -258,7 +258,7 @@
|
|||||||
- delete_mapping is not changed
|
- delete_mapping is not changed
|
||||||
|
|
||||||
- name: 'Delete mapping (retry - no change) '
|
- name: 'Delete mapping (retry - no change) '
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
register: delete_mapping
|
register: delete_mapping
|
||||||
@ -268,7 +268,7 @@
|
|||||||
- delete_mapping is not changed
|
- delete_mapping is not changed
|
||||||
|
|
||||||
- name: 'Fetch mapping info after deletion'
|
- name: 'Fetch mapping info after deletion'
|
||||||
openstack.cloud.os_keystone_mapping_info:
|
openstack.cloud.federation_mapping_info:
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
register: mapping_info
|
register: mapping_info
|
||||||
ignore_errors: True
|
ignore_errors: True
|
||||||
@ -277,7 +277,7 @@
|
|||||||
- mapping_info is failed
|
- mapping_info is failed
|
||||||
|
|
||||||
- name: 'Delete second mapping'
|
- name: 'Delete second mapping'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name_2 }}'
|
name: '{{ mapping_name_2 }}'
|
||||||
register: delete_mapping
|
register: delete_mapping
|
||||||
@ -288,13 +288,13 @@
|
|||||||
|
|
||||||
always:
|
always:
|
||||||
- name: 'Delete mapping'
|
- name: 'Delete mapping'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name }}'
|
name: '{{ mapping_name }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
|
||||||
- name: 'Delete second mapping'
|
- name: 'Delete second mapping'
|
||||||
openstack.cloud.os_keystone_mapping:
|
openstack.cloud.federation_mapping:
|
||||||
state: 'absent'
|
state: 'absent'
|
||||||
name: '{{ mapping_name_2 }}'
|
name: '{{ mapping_name_2 }}'
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
- name: Create keystone role
|
- name: Create keystone role
|
||||||
openstack.cloud.os_keystone_role:
|
openstack.cloud.identity_role:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ role_name }}"
|
name: "{{ role_name }}"
|
||||||
|
|
||||||
- name: Delete keystone role
|
- name: Delete keystone role
|
||||||
openstack.cloud.os_keystone_role:
|
openstack.cloud.identity_role:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ role_name }}"
|
name: "{{ role_name }}"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create network
|
- name: Create network
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
state: present
|
state: present
|
||||||
@ -8,7 +8,7 @@
|
|||||||
external: "{{ network_external }}"
|
external: "{{ network_external }}"
|
||||||
|
|
||||||
- name: Delete network
|
- name: Delete network
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create public flavor
|
- name: Create public flavor
|
||||||
openstack.cloud.os_nova_flavor:
|
openstack.cloud.compute_flavor:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_public_flavor
|
name: ansible_public_flavor
|
||||||
@ -13,13 +13,13 @@
|
|||||||
flavorid: 12345
|
flavorid: 12345
|
||||||
|
|
||||||
- name: Delete public flavor
|
- name: Delete public flavor
|
||||||
openstack.cloud.os_nova_flavor:
|
openstack.cloud.compute_flavor:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: ansible_public_flavor
|
name: ansible_public_flavor
|
||||||
|
|
||||||
- name: Create private flavor
|
- name: Create private flavor
|
||||||
openstack.cloud.os_nova_flavor:
|
openstack.cloud.compute_flavor:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_private_flavor
|
name: ansible_private_flavor
|
||||||
@ -32,13 +32,13 @@
|
|||||||
flavorid: 12345
|
flavorid: 12345
|
||||||
|
|
||||||
- name: Delete private flavor
|
- name: Delete private flavor
|
||||||
openstack.cloud.os_nova_flavor:
|
openstack.cloud.compute_flavor:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: ansible_private_flavor
|
name: ansible_private_flavor
|
||||||
|
|
||||||
- name: Create flavor (defaults)
|
- name: Create flavor (defaults)
|
||||||
openstack.cloud.os_nova_flavor:
|
openstack.cloud.compute_flavor:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_defaults_flavor
|
name: ansible_defaults_flavor
|
||||||
@ -47,7 +47,7 @@
|
|||||||
disk: 10
|
disk: 10
|
||||||
|
|
||||||
- name: Delete flavor (defaults)
|
- name: Delete flavor (defaults)
|
||||||
openstack.cloud.os_nova_flavor:
|
openstack.cloud.compute_flavor:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: ansible_defaults_flavor
|
name: ansible_defaults_flavor
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
register: tmp_file
|
register: tmp_file
|
||||||
|
|
||||||
- name: Create container
|
- name: Create container
|
||||||
openstack.cloud.os_object:
|
openstack.cloud.object:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
container: ansible_container
|
container: ansible_container
|
||||||
container_access: private
|
container_access: private
|
||||||
|
|
||||||
- name: Put object
|
- name: Put object
|
||||||
openstack.cloud.os_object:
|
openstack.cloud.object:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_object
|
name: ansible_object
|
||||||
@ -19,14 +19,14 @@
|
|||||||
container: ansible_container
|
container: ansible_container
|
||||||
|
|
||||||
- name: Delete object
|
- name: Delete object
|
||||||
openstack.cloud.os_object:
|
openstack.cloud.object:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: ansible_object
|
name: ansible_object
|
||||||
container: ansible_container
|
container: ansible_container
|
||||||
|
|
||||||
- name: Delete container
|
- name: Delete container
|
||||||
openstack.cloud.os_object:
|
openstack.cloud.object:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
container: ansible_container
|
container: ansible_container
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
---
|
---
|
||||||
- name: Create network
|
- name: Create network
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
external: "{{ network_external }}"
|
external: "{{ network_external }}"
|
||||||
|
|
||||||
- name: Create subnet
|
- name: Create subnet
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ subnet_name }}"
|
name: "{{ subnet_name }}"
|
||||||
@ -15,7 +15,7 @@
|
|||||||
cidr: 10.5.5.0/24
|
cidr: 10.5.5.0/24
|
||||||
|
|
||||||
- name: Create port (no security group or default security group)
|
- name: Create port (no security group or default security group)
|
||||||
openstack.cloud.os_port:
|
openstack.cloud.port:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ port_name }}"
|
name: "{{ port_name }}"
|
||||||
@ -28,20 +28,20 @@
|
|||||||
- debug: var=port
|
- debug: var=port
|
||||||
|
|
||||||
- name: Delete port (no security group or default security group)
|
- name: Delete port (no security group or default security group)
|
||||||
openstack.cloud.os_port:
|
openstack.cloud.port:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ port_name }}"
|
name: "{{ port_name }}"
|
||||||
|
|
||||||
- name: Create security group
|
- name: Create security group
|
||||||
openstack.cloud.os_security_group:
|
openstack.cloud.security_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ secgroup_name }}"
|
name: "{{ secgroup_name }}"
|
||||||
description: Test group
|
description: Test group
|
||||||
|
|
||||||
- name: Create port (with security group)
|
- name: Create port (with security group)
|
||||||
openstack.cloud.os_port:
|
openstack.cloud.port:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ port_name }}"
|
name: "{{ port_name }}"
|
||||||
@ -55,13 +55,13 @@
|
|||||||
- debug: var=port
|
- debug: var=port
|
||||||
|
|
||||||
- name: Delete port (with security group)
|
- name: Delete port (with security group)
|
||||||
openstack.cloud.os_port:
|
openstack.cloud.port:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ port_name }}"
|
name: "{{ port_name }}"
|
||||||
|
|
||||||
- name: Create port (with allowed_address_pairs and extra_dhcp_opts)
|
- name: Create port (with allowed_address_pairs and extra_dhcp_opts)
|
||||||
openstack.cloud.os_port:
|
openstack.cloud.port:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ port_name }}"
|
name: "{{ port_name }}"
|
||||||
@ -77,25 +77,25 @@
|
|||||||
- debug: var=port
|
- debug: var=port
|
||||||
|
|
||||||
- name: Delete port (with allowed_address_pairs and extra_dhcp_opts)
|
- name: Delete port (with allowed_address_pairs and extra_dhcp_opts)
|
||||||
openstack.cloud.os_port:
|
openstack.cloud.port:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ port_name }}"
|
name: "{{ port_name }}"
|
||||||
|
|
||||||
- name: Delete security group
|
- name: Delete security group
|
||||||
openstack.cloud.os_security_group:
|
openstack.cloud.security_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ secgroup_name }}"
|
name: "{{ secgroup_name }}"
|
||||||
|
|
||||||
- name: Delete subnet
|
- name: Delete subnet
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ subnet_name }}"
|
name: "{{ subnet_name }}"
|
||||||
|
|
||||||
- name: Delete network
|
- name: Delete network
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create project
|
- name: Create project
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -12,7 +12,7 @@
|
|||||||
- debug: var=project
|
- debug: var=project
|
||||||
|
|
||||||
- name: Update project
|
- name: Update project
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -22,7 +22,7 @@
|
|||||||
- debug: var=updatedproject
|
- debug: var=updatedproject
|
||||||
|
|
||||||
- name: Delete project
|
- name: Delete project
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
- name: 'Create project with properties - CHECK_MODE'
|
- name: 'Create project with properties - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -17,7 +17,7 @@
|
|||||||
- create_project_cm is changed
|
- create_project_cm is changed
|
||||||
|
|
||||||
- name: 'Create project with properties'
|
- name: 'Create project with properties'
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
- name: 'Create project with properties (retry - no change) - CHECK_MODE'
|
- name: 'Create project with properties (retry - no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -53,7 +53,7 @@
|
|||||||
- create_project_retry_cm is not changed
|
- create_project_retry_cm is not changed
|
||||||
|
|
||||||
- name: 'Create project with properties (retry - no change)'
|
- name: 'Create project with properties (retry - no change)'
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -73,7 +73,7 @@
|
|||||||
|
|
||||||
- name: 'Update project with properties - CHECK_MODE'
|
- name: 'Update project with properties - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -87,7 +87,7 @@
|
|||||||
- updated_project_cm is changed
|
- updated_project_cm is changed
|
||||||
|
|
||||||
- name: 'Update project with properties'
|
- name: 'Update project with properties'
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -105,7 +105,7 @@
|
|||||||
|
|
||||||
- name: 'Update project with properties (retry - no change) - CHECK_MODE'
|
- name: 'Update project with properties (retry - no change) - CHECK_MODE'
|
||||||
check_mode: yes
|
check_mode: yes
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -119,7 +119,7 @@
|
|||||||
- updated_project_retry_cm is not changed
|
- updated_project_retry_cm is not changed
|
||||||
|
|
||||||
- name: 'Update project with properties (retry - no change)'
|
- name: 'Update project with properties (retry - no change)'
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
@ -136,7 +136,7 @@
|
|||||||
- updated_project_retry["project"].dummy_key == dummy_value_updated
|
- updated_project_retry["project"].dummy_key == dummy_value_updated
|
||||||
|
|
||||||
- name: Delete project with properties
|
- name: Delete project with properties
|
||||||
openstack.cloud.os_project:
|
openstack.cloud.project:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: ansible_project
|
name: ansible_project
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
---
|
---
|
||||||
# Regular user operation
|
# Regular user operation
|
||||||
- name: Create internal network
|
- name: Create internal network
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
external: false
|
external: false
|
||||||
|
|
||||||
- name: Create subnet1
|
- name: Create subnet1
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
network_name: "{{ network_name }}"
|
network_name: "{{ network_name }}"
|
||||||
@ -16,13 +16,13 @@
|
|||||||
cidr: 10.7.7.0/24
|
cidr: 10.7.7.0/24
|
||||||
|
|
||||||
- name: Create router
|
- name: Create router
|
||||||
openstack.cloud.os_router:
|
openstack.cloud.router:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ router_name }}"
|
name: "{{ router_name }}"
|
||||||
|
|
||||||
- name: Update router (add interface)
|
- name: Update router (add interface)
|
||||||
openstack.cloud.os_router:
|
openstack.cloud.router:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ router_name }}"
|
name: "{{ router_name }}"
|
||||||
@ -30,7 +30,7 @@
|
|||||||
- shade_subnet1
|
- shade_subnet1
|
||||||
|
|
||||||
- name: Gather routers info
|
- name: Gather routers info
|
||||||
openstack.cloud.os_routers_info:
|
openstack.cloud.routers_info:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ router_name }}"
|
name: "{{ router_name }}"
|
||||||
filters:
|
filters:
|
||||||
@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
# Admin operation
|
# Admin operation
|
||||||
- name: Create external network
|
- name: Create external network
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ external_network_name }}"
|
name: "{{ external_network_name }}"
|
||||||
@ -54,7 +54,7 @@
|
|||||||
- network_external
|
- network_external
|
||||||
|
|
||||||
- name: Create subnet2
|
- name: Create subnet2
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
network_name: "{{ external_network_name }}"
|
network_name: "{{ external_network_name }}"
|
||||||
@ -64,7 +64,7 @@
|
|||||||
- network_external
|
- network_external
|
||||||
|
|
||||||
- name: Update router (add external gateway)
|
- name: Update router (add external gateway)
|
||||||
openstack.cloud.os_router:
|
openstack.cloud.router:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ router_name }}"
|
name: "{{ router_name }}"
|
||||||
@ -75,7 +75,7 @@
|
|||||||
- network_external
|
- network_external
|
||||||
|
|
||||||
- name: Gather routers info
|
- name: Gather routers info
|
||||||
openstack.cloud.os_routers_info:
|
openstack.cloud.routers_info:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ router_name }}"
|
name: "{{ router_name }}"
|
||||||
filters:
|
filters:
|
||||||
@ -89,19 +89,19 @@
|
|||||||
- (result.openstack_routers.0.interfaces_info|length) == 1
|
- (result.openstack_routers.0.interfaces_info|length) == 1
|
||||||
|
|
||||||
- name: Delete router
|
- name: Delete router
|
||||||
openstack.cloud.os_router:
|
openstack.cloud.router:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ router_name }}"
|
name: "{{ router_name }}"
|
||||||
|
|
||||||
- name: Delete subnet1
|
- name: Delete subnet1
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: shade_subnet1
|
name: shade_subnet1
|
||||||
|
|
||||||
- name: Delete subnet2
|
- name: Delete subnet2
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: shade_subnet2
|
name: shade_subnet2
|
||||||
@ -109,13 +109,13 @@
|
|||||||
- network_external
|
- network_external
|
||||||
|
|
||||||
- name: Delete internal network
|
- name: Delete internal network
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
|
|
||||||
- name: Delete external network
|
- name: Delete external network
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ external_network_name }}"
|
name: "{{ external_network_name }}"
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
---
|
---
|
||||||
- name: Create security group
|
- name: Create security group
|
||||||
openstack.cloud.os_security_group:
|
openstack.cloud.security_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ secgroup_name }}"
|
name: "{{ secgroup_name }}"
|
||||||
state: present
|
state: present
|
||||||
description: Created from Ansible playbook
|
description: Created from Ansible playbook
|
||||||
|
|
||||||
- name: Create empty ICMP rule
|
- name: Create empty ICMP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: present
|
state: present
|
||||||
@ -15,7 +15,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Create -1 ICMP rule
|
- name: Create -1 ICMP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: present
|
state: present
|
||||||
@ -25,7 +25,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Create empty TCP rule
|
- name: Create empty TCP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: present
|
state: present
|
||||||
@ -33,7 +33,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Create empty UDP rule
|
- name: Create empty UDP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: present
|
state: present
|
||||||
@ -41,7 +41,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Create HTTP rule
|
- name: Create HTTP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: present
|
state: present
|
||||||
@ -51,7 +51,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Create egress rule
|
- name: Create egress rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: present
|
state: present
|
||||||
@ -62,7 +62,7 @@
|
|||||||
direction: egress
|
direction: egress
|
||||||
|
|
||||||
- name: Delete empty ICMP rule
|
- name: Delete empty ICMP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
@ -70,7 +70,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Delete -1 ICMP rule
|
- name: Delete -1 ICMP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
@ -80,7 +80,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Delete empty TCP rule
|
- name: Delete empty TCP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
@ -88,7 +88,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Delete empty UDP rule
|
- name: Delete empty UDP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
@ -96,7 +96,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Delete HTTP rule
|
- name: Delete HTTP rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
@ -106,7 +106,7 @@
|
|||||||
remote_ip_prefix: 0.0.0.0/0
|
remote_ip_prefix: 0.0.0.0/0
|
||||||
|
|
||||||
- name: Delete egress rule
|
- name: Delete egress rule
|
||||||
openstack.cloud.os_security_group_rule:
|
openstack.cloud.security_group_rule:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
security_group: "{{ secgroup_name }}"
|
security_group: "{{ secgroup_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
@ -117,7 +117,7 @@
|
|||||||
direction: egress
|
direction: egress
|
||||||
|
|
||||||
- name: Delete security group
|
- name: Delete security group
|
||||||
openstack.cloud.os_security_group:
|
openstack.cloud.security_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ secgroup_name }}"
|
name: "{{ secgroup_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create server with meta as CSV
|
- name: Create server with meta as CSV
|
||||||
openstack.cloud.os_server:
|
openstack.cloud.server:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ server_name }}"
|
name: "{{ server_name }}"
|
||||||
@ -15,14 +15,14 @@
|
|||||||
- debug: var=server
|
- debug: var=server
|
||||||
|
|
||||||
- name: Delete server with meta as CSV
|
- name: Delete server with meta as CSV
|
||||||
openstack.cloud.os_server:
|
openstack.cloud.server:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ server_name }}"
|
name: "{{ server_name }}"
|
||||||
wait: true
|
wait: true
|
||||||
|
|
||||||
- name: Create server with meta as dict
|
- name: Create server with meta as dict
|
||||||
openstack.cloud.os_server:
|
openstack.cloud.server:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ server_name }}"
|
name: "{{ server_name }}"
|
||||||
@ -39,14 +39,14 @@
|
|||||||
- debug: var=server
|
- debug: var=server
|
||||||
|
|
||||||
- name: Delete server with meta as dict
|
- name: Delete server with meta as dict
|
||||||
openstack.cloud.os_server:
|
openstack.cloud.server:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ server_name }}"
|
name: "{{ server_name }}"
|
||||||
wait: true
|
wait: true
|
||||||
|
|
||||||
- name: Create server (FIP from pool/network)
|
- name: Create server (FIP from pool/network)
|
||||||
openstack.cloud.os_server:
|
openstack.cloud.server:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ server_name }}"
|
name: "{{ server_name }}"
|
||||||
@ -61,14 +61,14 @@
|
|||||||
- debug: var=server
|
- debug: var=server
|
||||||
|
|
||||||
- name: Delete server (FIP from pool/network)
|
- name: Delete server (FIP from pool/network)
|
||||||
openstack.cloud.os_server:
|
openstack.cloud.server:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ server_name }}"
|
name: "{{ server_name }}"
|
||||||
wait: true
|
wait: true
|
||||||
|
|
||||||
- name: Create server from volume
|
- name: Create server from volume
|
||||||
openstack.cloud.os_server:
|
openstack.cloud.server:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ server_name }}"
|
name: "{{ server_name }}"
|
||||||
@ -85,7 +85,7 @@
|
|||||||
- debug: var=server
|
- debug: var=server
|
||||||
|
|
||||||
- name: Delete server with volume
|
- name: Delete server with volume
|
||||||
openstack.cloud.os_server:
|
openstack.cloud.server:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ server_name }}"
|
name: "{{ server_name }}"
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
- name: Create network {{ network_name }}
|
- name: Create network {{ network_name }}
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Create subnet {{ subnet_name }} on network {{ network_name }}
|
- name: Create subnet {{ subnet_name }} on network {{ network_name }}
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
network_name: "{{ network_name }}"
|
network_name: "{{ network_name }}"
|
||||||
name: "{{ subnet_name }}"
|
name: "{{ subnet_name }}"
|
||||||
@ -21,7 +21,7 @@
|
|||||||
allocation_pool_end: 192.168.0.254
|
allocation_pool_end: 192.168.0.254
|
||||||
|
|
||||||
- name: Update subnet
|
- name: Update subnet
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
network_name: "{{ network_name }}"
|
network_name: "{{ network_name }}"
|
||||||
name: "{{ subnet_name }}"
|
name: "{{ subnet_name }}"
|
||||||
@ -31,13 +31,13 @@
|
|||||||
cidr: 192.168.0.0/24
|
cidr: 192.168.0.0/24
|
||||||
|
|
||||||
- name: Delete subnet {{ subnet_name }}
|
- name: Delete subnet {{ subnet_name }}
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ subnet_name }}"
|
name: "{{ subnet_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: Delete network {{ network_name }}
|
- name: Delete network {{ network_name }}
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
- name: Create network {{ network_name }}
|
- name: Create network {{ network_name }}
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
- name: Create subnet {{ subnet_name }} on network {{ network_name }}
|
- name: Create subnet {{ subnet_name }} on network {{ network_name }}
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
network_name: "{{ network_name }}"
|
network_name: "{{ network_name }}"
|
||||||
enable_dhcp: "{{ enable_subnet_dhcp }}"
|
enable_dhcp: "{{ enable_subnet_dhcp }}"
|
||||||
@ -18,7 +18,7 @@
|
|||||||
allocation_pool_end: 192.168.0.4
|
allocation_pool_end: 192.168.0.4
|
||||||
|
|
||||||
- name: Update subnet {{ subnet_name }} allocation pools
|
- name: Update subnet {{ subnet_name }} allocation pools
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
network_name: "{{ network_name }}"
|
network_name: "{{ network_name }}"
|
||||||
name: "{{ subnet_name }}"
|
name: "{{ subnet_name }}"
|
||||||
@ -28,7 +28,7 @@
|
|||||||
allocation_pool_end: 192.168.0.8
|
allocation_pool_end: 192.168.0.8
|
||||||
|
|
||||||
- name: Get Subnet Info
|
- name: Get Subnet Info
|
||||||
openstack.cloud.os_subnets_info:
|
openstack.cloud.subnets_info:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ subnet_name }}"
|
name: "{{ subnet_name }}"
|
||||||
register: subnet_result
|
register: subnet_result
|
||||||
@ -51,13 +51,13 @@
|
|||||||
- {start: '192.168.0.5', end: '192.168.0.8'}
|
- {start: '192.168.0.5', end: '192.168.0.8'}
|
||||||
|
|
||||||
- name: Delete subnet {{ subnet_name }}
|
- name: Delete subnet {{ subnet_name }}
|
||||||
openstack.cloud.os_subnet:
|
openstack.cloud.subnet:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ subnet_name }}"
|
name: "{{ subnet_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
|
||||||
- name: Delete network {{ network_name }}
|
- name: Delete network {{ network_name }}
|
||||||
openstack.cloud.os_network:
|
openstack.cloud.network:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
name: "{{ network_name }}"
|
name: "{{ network_name }}"
|
||||||
state: absent
|
state: absent
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create user
|
- name: Create user
|
||||||
openstack.cloud.os_user:
|
openstack.cloud.identity_user:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_user
|
name: ansible_user
|
||||||
@ -13,7 +13,7 @@
|
|||||||
- debug: var=user
|
- debug: var=user
|
||||||
|
|
||||||
- name: Update user
|
- name: Update user
|
||||||
openstack.cloud.os_user:
|
openstack.cloud.identity_user:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_user
|
name: ansible_user
|
||||||
@ -24,7 +24,7 @@
|
|||||||
- debug: var=updateduser
|
- debug: var=updateduser
|
||||||
|
|
||||||
- name: Delete user
|
- name: Delete user
|
||||||
openstack.cloud.os_user:
|
openstack.cloud.identity_user:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: ansible_user
|
name: ansible_user
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create user
|
- name: Create user
|
||||||
openstack.cloud.os_user:
|
openstack.cloud.identity_user:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: ansible_user
|
name: ansible_user
|
||||||
@ -11,21 +11,21 @@
|
|||||||
register: user
|
register: user
|
||||||
|
|
||||||
- name: Assign user to nonadmins group
|
- name: Assign user to nonadmins group
|
||||||
openstack.cloud.os_user_group:
|
openstack.cloud.group_assignment:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
user: ansible_user
|
user: ansible_user
|
||||||
group: nonadmins
|
group: nonadmins
|
||||||
|
|
||||||
- name: Remove user from nonadmins group
|
- name: Remove user from nonadmins group
|
||||||
openstack.cloud.os_user_group:
|
openstack.cloud.group_assignment:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
user: ansible_user
|
user: ansible_user
|
||||||
group: nonadmins
|
group: nonadmins
|
||||||
|
|
||||||
- name: Delete user
|
- name: Delete user
|
||||||
openstack.cloud.os_user:
|
openstack.cloud.identity_user:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: ansible_user
|
name: ansible_user
|
||||||
|
@ -1,96 +1,96 @@
|
|||||||
- name: Create domain
|
- name: Create domain
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ domain_name }}"
|
name: "{{ domain_name }}"
|
||||||
register: domain
|
register: domain
|
||||||
|
|
||||||
- name: Create group in default domain
|
- name: Create group in default domain
|
||||||
openstack.cloud.os_group:
|
openstack.cloud.identity_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ group_name }}"
|
name: "{{ group_name }}"
|
||||||
domain_id: default
|
domain_id: default
|
||||||
|
|
||||||
- name: Create group in specific domain
|
- name: Create group in specific domain
|
||||||
openstack.cloud.os_group:
|
openstack.cloud.identity_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ group_name }}"
|
name: "{{ group_name }}"
|
||||||
domain_id: "{{ domain.id }}"
|
domain_id: "{{ domain.id }}"
|
||||||
|
|
||||||
- name: Create user in default domain
|
- name: Create user in default domain
|
||||||
openstack.cloud.os_user:
|
openstack.cloud.identity_user:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ user_name }}"
|
name: "{{ user_name }}"
|
||||||
domain: default
|
domain: default
|
||||||
|
|
||||||
- name: Create user in specific domain
|
- name: Create user in specific domain
|
||||||
openstack.cloud.os_user:
|
openstack.cloud.identity_user:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
name: "{{ user_name }}"
|
name: "{{ user_name }}"
|
||||||
domain: "{{ domain.id }}"
|
domain: "{{ domain.id }}"
|
||||||
|
|
||||||
- name: Assign role to group in default domain
|
- name: Assign role to group in default domain
|
||||||
openstack.cloud.os_user_role:
|
openstack.cloud.role_assignment:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
role: "{{ keystone_role_name }}"
|
role: "{{ keystone_role_name }}"
|
||||||
group: "{{ group_name }}"
|
group: "{{ group_name }}"
|
||||||
domain: default
|
domain: default
|
||||||
|
|
||||||
- name: Assign role to group in specific domain
|
- name: Assign role to group in specific domain
|
||||||
openstack.cloud.os_user_role:
|
openstack.cloud.role_assignment:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
role: "{{ keystone_role_name }}"
|
role: "{{ keystone_role_name }}"
|
||||||
group: "{{ group_name }}"
|
group: "{{ group_name }}"
|
||||||
domain: "{{ domain.id }}"
|
domain: "{{ domain.id }}"
|
||||||
|
|
||||||
- name: Assign role to user in default domain
|
- name: Assign role to user in default domain
|
||||||
openstack.cloud.os_user_role:
|
openstack.cloud.role_assignment:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
role: "{{ keystone_role_name }}"
|
role: "{{ keystone_role_name }}"
|
||||||
user: "{{ user_name }}"
|
user: "{{ user_name }}"
|
||||||
domain: default
|
domain: default
|
||||||
|
|
||||||
- name: Assign role to user in specific domain
|
- name: Assign role to user in specific domain
|
||||||
openstack.cloud.os_user_role:
|
openstack.cloud.role_assignment:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
role: "{{ keystone_role_name }}"
|
role: "{{ keystone_role_name }}"
|
||||||
user: "{{ user_name }}"
|
user: "{{ user_name }}"
|
||||||
domain: "{{ domain.id }}"
|
domain: "{{ domain.id }}"
|
||||||
|
|
||||||
- name: Delete group in default domain
|
- name: Delete group in default domain
|
||||||
openstack.cloud.os_group:
|
openstack.cloud.identity_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ group_name }}"
|
name: "{{ group_name }}"
|
||||||
domain_id: default
|
domain_id: default
|
||||||
|
|
||||||
- name: Delete group in specific domain
|
- name: Delete group in specific domain
|
||||||
openstack.cloud.os_group:
|
openstack.cloud.identity_group:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ group_name }}"
|
name: "{{ group_name }}"
|
||||||
domain_id: "{{ domain.id }}"
|
domain_id: "{{ domain.id }}"
|
||||||
|
|
||||||
- name: Delete user in default domain
|
- name: Delete user in default domain
|
||||||
openstack.cloud.os_user:
|
openstack.cloud.identity_user:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ user_name }}"
|
name: "{{ user_name }}"
|
||||||
domain: default
|
domain: default
|
||||||
|
|
||||||
- name: Delete user in specific domain
|
- name: Delete user in specific domain
|
||||||
openstack.cloud.os_user:
|
openstack.cloud.identity_user:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ user_name }}"
|
name: "{{ user_name }}"
|
||||||
domain: "{{ domain.id }}"
|
domain: "{{ domain.id }}"
|
||||||
|
|
||||||
- name: Delete domain
|
- name: Delete domain
|
||||||
openstack.cloud.os_keystone_domain:
|
openstack.cloud.identity_domain:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
name: "{{ domain_name }}"
|
name: "{{ domain_name }}"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
- name: Create volume
|
- name: Create volume
|
||||||
openstack.cloud.os_volume:
|
openstack.cloud.volume:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: present
|
state: present
|
||||||
size: 1
|
size: 1
|
||||||
@ -11,7 +11,7 @@
|
|||||||
- debug: var=vol
|
- debug: var=vol
|
||||||
|
|
||||||
- name: Delete volume
|
- name: Delete volume
|
||||||
openstack.cloud.os_volume:
|
openstack.cloud.volume:
|
||||||
cloud: "{{ cloud }}"
|
cloud: "{{ cloud }}"
|
||||||
state: absent
|
state: absent
|
||||||
display_name: ansible_volume
|
display_name: ansible_volume
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
- { role: auth, tags: auth }
|
- { role: auth, tags: auth }
|
||||||
- { role: client_config, tags: client_config }
|
- { role: client_config, tags: client_config }
|
||||||
- { role: group, tags: group }
|
- { role: group, tags: group }
|
||||||
# TODO(mordred) Reenable this once the fixed os_image winds up in an
|
# TODO(mordred) Reenable this once the fixed openstack.cloud.image winds up in an
|
||||||
# upstream ansible release.
|
# upstream ansible release.
|
||||||
# - { role: image, tags: image }
|
# - { role: image, tags: image }
|
||||||
- { role: keypair, tags: keypair }
|
- { role: keypair, tags: keypair }
|
||||||
|
@ -1,38 +1,240 @@
|
|||||||
|
openstack:
|
||||||
|
- auth
|
||||||
|
- baremetal_inspect
|
||||||
|
- baremetal_inspect
|
||||||
|
- baremetal_node
|
||||||
|
- baremetal_node
|
||||||
|
- baremetal_node_action
|
||||||
|
- baremetal_node_action
|
||||||
|
- catalog_endpoint
|
||||||
|
- catalog_service
|
||||||
|
- catalog_service
|
||||||
|
- coe_cluster
|
||||||
|
- coe_cluster_template
|
||||||
|
- compute_flavor
|
||||||
|
- compute_flavor
|
||||||
|
- compute_flavor
|
||||||
|
- compute_flavor_info
|
||||||
|
- compute_flavor_info
|
||||||
|
- config
|
||||||
|
- config
|
||||||
|
- dns_zone
|
||||||
|
- dns_zone
|
||||||
|
- endpoint
|
||||||
|
- endpoint
|
||||||
|
- federation_idp
|
||||||
|
- federation_idp
|
||||||
|
- federation_idp_info
|
||||||
|
- federation_idp_info
|
||||||
|
- federation_mapping
|
||||||
|
- federation_mapping
|
||||||
|
- federation_mapping_info
|
||||||
|
- federation_mapping_info
|
||||||
|
- floating_ip
|
||||||
|
- group_assignment
|
||||||
|
- group_assignment
|
||||||
|
- host_aggregate
|
||||||
|
- host_aggregate
|
||||||
|
- identity_domain
|
||||||
|
- identity_domain
|
||||||
|
- identity_domain_info
|
||||||
|
- identity_domain_info
|
||||||
|
- identity_group
|
||||||
|
- identity_group
|
||||||
|
- identity_group_info
|
||||||
|
- identity_group_info
|
||||||
|
- identity_role
|
||||||
|
- identity_role
|
||||||
|
- identity_user
|
||||||
|
- identity_user
|
||||||
|
- identity_user_info
|
||||||
|
- identity_user_info
|
||||||
|
- image
|
||||||
|
- image_info
|
||||||
|
- keypair
|
||||||
|
- keystone_federation_protocol
|
||||||
|
- keystone_federation_protocol_info
|
||||||
|
- lb_listener
|
||||||
|
- lb_listener
|
||||||
|
- lb_member
|
||||||
|
- lb_member
|
||||||
|
- lb_pool
|
||||||
|
- lb_pool
|
||||||
|
- loadbalancer
|
||||||
|
- network
|
||||||
|
- networks_info
|
||||||
|
- object
|
||||||
|
- port
|
||||||
|
- port_info
|
||||||
|
- project
|
||||||
|
- project_access
|
||||||
|
- project_info
|
||||||
|
- quota
|
||||||
|
- recordset
|
||||||
|
- role_assignment
|
||||||
|
- role_assignment
|
||||||
|
- router
|
||||||
|
- routers_info
|
||||||
|
- security_group
|
||||||
|
- security_group_rule
|
||||||
|
- server
|
||||||
|
- server_action
|
||||||
|
- server_group
|
||||||
|
- server_info
|
||||||
|
- server_metadata
|
||||||
|
- server_volume
|
||||||
|
- stack
|
||||||
|
- subnet
|
||||||
|
- subnets_info
|
||||||
|
- volume
|
||||||
|
- volume_snapshot
|
||||||
os:
|
os:
|
||||||
|
- auth
|
||||||
|
- baremetal_inspect
|
||||||
|
- baremetal_inspect
|
||||||
|
- baremetal_node
|
||||||
|
- baremetal_node
|
||||||
|
- baremetal_node_action
|
||||||
|
- baremetal_node_action
|
||||||
|
- catalog_endpoint
|
||||||
|
- catalog_service
|
||||||
|
- catalog_service
|
||||||
|
- coe_cluster
|
||||||
|
- coe_cluster_template
|
||||||
|
- compute_flavor
|
||||||
|
- compute_flavor
|
||||||
|
- compute_flavor
|
||||||
|
- compute_flavor_info
|
||||||
|
- compute_flavor_info
|
||||||
|
- config
|
||||||
|
- config
|
||||||
|
- dns_zone
|
||||||
|
- dns_zone
|
||||||
|
- endpoint
|
||||||
|
- endpoint
|
||||||
|
- federation_idp
|
||||||
|
- federation_idp
|
||||||
|
- federation_idp_info
|
||||||
|
- federation_idp_info
|
||||||
|
- federation_mapping
|
||||||
|
- federation_mapping
|
||||||
|
- federation_mapping_info
|
||||||
|
- federation_mapping_info
|
||||||
|
- floating_ip
|
||||||
|
- group_assignment
|
||||||
|
- group_assignment
|
||||||
|
- host_aggregate
|
||||||
|
- host_aggregate
|
||||||
|
- identity_domain
|
||||||
|
- identity_domain
|
||||||
|
- identity_domain_info
|
||||||
|
- identity_domain_info
|
||||||
|
- identity_group
|
||||||
|
- identity_group
|
||||||
|
- identity_group_info
|
||||||
|
- identity_group_info
|
||||||
|
- identity_role
|
||||||
|
- identity_role
|
||||||
|
- identity_user
|
||||||
|
- identity_user
|
||||||
|
- identity_user_info
|
||||||
|
- identity_user_info
|
||||||
|
- image
|
||||||
|
- image_info
|
||||||
|
- keypair
|
||||||
|
- keystone_federation_protocol
|
||||||
|
- keystone_federation_protocol_info
|
||||||
|
- lb_listener
|
||||||
|
- lb_listener
|
||||||
|
- lb_member
|
||||||
|
- lb_member
|
||||||
|
- lb_pool
|
||||||
|
- lb_pool
|
||||||
|
- loadbalancer
|
||||||
|
- network
|
||||||
|
- networks_info
|
||||||
|
- object
|
||||||
|
- port
|
||||||
|
- port_info
|
||||||
|
- project
|
||||||
|
- project_access
|
||||||
|
- project_info
|
||||||
|
- quota
|
||||||
|
- recordset
|
||||||
|
- role_assignment
|
||||||
|
- role_assignment
|
||||||
|
- router
|
||||||
|
- routers_info
|
||||||
|
- security_group
|
||||||
|
- security_group_rule
|
||||||
|
- server
|
||||||
|
- server_action
|
||||||
|
- server_group
|
||||||
|
- server_info
|
||||||
|
- server_metadata
|
||||||
|
- server_volume
|
||||||
|
- stack
|
||||||
|
- subnet
|
||||||
|
- subnets_info
|
||||||
|
- volume
|
||||||
|
- volume_snapshot
|
||||||
- os_auth
|
- os_auth
|
||||||
- os_client_config
|
- os_client_config
|
||||||
|
- os_client_config
|
||||||
- os_coe_cluster
|
- os_coe_cluster
|
||||||
- os_coe_cluster_template
|
- os_coe_cluster_template
|
||||||
|
- os_endpoint
|
||||||
|
- os_flavor
|
||||||
|
- os_flavor_info
|
||||||
- os_flavor_info
|
- os_flavor_info
|
||||||
- os_floating_ip
|
- os_floating_ip
|
||||||
- os_group
|
- os_group
|
||||||
|
- os_group
|
||||||
|
- os_group_info
|
||||||
- os_group_info
|
- os_group_info
|
||||||
- os_image
|
- os_image
|
||||||
- os_image_info
|
- os_image_info
|
||||||
- os_ironic
|
- os_ironic
|
||||||
|
- os_ironic
|
||||||
- os_ironic_inspect
|
- os_ironic_inspect
|
||||||
|
- os_ironic_inspect
|
||||||
|
- os_ironic_node
|
||||||
- os_ironic_node
|
- os_ironic_node
|
||||||
- os_keypair
|
- os_keypair
|
||||||
- os_keystone_domain
|
- os_keystone_domain
|
||||||
|
- os_keystone_domain
|
||||||
|
- os_keystone_domain_info
|
||||||
- os_keystone_domain_info
|
- os_keystone_domain_info
|
||||||
- os_keystone_endpoint
|
- os_keystone_endpoint
|
||||||
- os_keystone_identity_provider
|
- os_keystone_endpoint
|
||||||
- os_keystone_identity_provider_info
|
|
||||||
- os_keystone_mapping
|
|
||||||
- os_keystone_mapping_info
|
|
||||||
- os_keystone_federation_protocol
|
- os_keystone_federation_protocol
|
||||||
- os_keystone_federation_protocol_info
|
- os_keystone_federation_protocol_info
|
||||||
|
- os_keystone_identity_provider
|
||||||
|
- os_keystone_identity_provider
|
||||||
|
- os_keystone_identity_provider_info
|
||||||
|
- os_keystone_identity_provider_info
|
||||||
|
- os_keystone_mapping
|
||||||
|
- os_keystone_mapping
|
||||||
|
- os_keystone_mapping_info
|
||||||
|
- os_keystone_mapping_info
|
||||||
|
- os_keystone_role
|
||||||
- os_keystone_role
|
- os_keystone_role
|
||||||
- os_keystone_service
|
- os_keystone_service
|
||||||
|
- os_keystone_service
|
||||||
|
- os_listener
|
||||||
- os_listener
|
- os_listener
|
||||||
- os_loadbalancer
|
- os_loadbalancer
|
||||||
- os_member
|
- os_member
|
||||||
|
- os_member
|
||||||
- os_network
|
- os_network
|
||||||
- os_networks_info
|
- os_networks_info
|
||||||
- os_nova_flavor
|
- os_nova_flavor
|
||||||
|
- os_nova_flavor
|
||||||
|
- os_nova_host_aggregate
|
||||||
- os_nova_host_aggregate
|
- os_nova_host_aggregate
|
||||||
- os_object
|
- os_object
|
||||||
- os_pool
|
- os_pool
|
||||||
|
- os_pool
|
||||||
- os_port
|
- os_port
|
||||||
- os_port_info
|
- os_port_info
|
||||||
- os_project
|
- os_project
|
||||||
@ -54,9 +256,14 @@ os:
|
|||||||
- os_subnet
|
- os_subnet
|
||||||
- os_subnets_info
|
- os_subnets_info
|
||||||
- os_user
|
- os_user
|
||||||
|
- os_user
|
||||||
|
- os_user_group
|
||||||
- os_user_group
|
- os_user_group
|
||||||
- os_user_info
|
- os_user_info
|
||||||
|
- os_user_info
|
||||||
|
- os_user_role
|
||||||
- os_user_role
|
- os_user_role
|
||||||
- os_volume
|
- os_volume
|
||||||
- os_volume_snapshot
|
- os_volume_snapshot
|
||||||
- os_zone
|
- os_zone
|
||||||
|
- os_zone
|
||||||
|
@ -20,6 +20,16 @@ plugin_routing:
|
|||||||
removal_date: TBD
|
removal_date: TBD
|
||||||
warning_text: os_ prefixed module names are deprecated, use openstack.cloud.coe_cluster_template
|
warning_text: os_ prefixed module names are deprecated, use openstack.cloud.coe_cluster_template
|
||||||
redirect: openstack.cloud.coe_cluster_template
|
redirect: openstack.cloud.coe_cluster_template
|
||||||
|
os_endpoint:
|
||||||
|
deprecation:
|
||||||
|
removal_date: TBD
|
||||||
|
warning_text: os_ prefixed module names are deprecated, use openstack.cloud.catalog_endpoint
|
||||||
|
redirect: openstack.cloud.catalog_endpoint
|
||||||
|
os_flavor:
|
||||||
|
deprecation:
|
||||||
|
removal_date: TBD
|
||||||
|
warning_text: os_ prefixed module names are deprecated, use openstack.cloud.compute_flavor
|
||||||
|
redirect: openstack.cloud.compute_flavor
|
||||||
os_flavor_info:
|
os_flavor_info:
|
||||||
deprecation:
|
deprecation:
|
||||||
removal_date: TBD
|
removal_date: TBD
|
||||||
|
73
plugins/modules/auth.py
Normal file
73
plugins/modules/auth.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: auth
|
||||||
|
short_description: Retrieve an auth token
|
||||||
|
author: "Monty Taylor (@emonty)"
|
||||||
|
description:
|
||||||
|
- Retrieve an auth token from an OpenStack Cloud
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Authenticate to the cloud and retrieve the service catalog
|
||||||
|
openstack.cloud.auth:
|
||||||
|
cloud: rax-dfw
|
||||||
|
|
||||||
|
- name: Show service catalog
|
||||||
|
debug:
|
||||||
|
var: service_catalog
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
auth_token:
|
||||||
|
description: Openstack API Auth Token
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
service_catalog:
|
||||||
|
description: A dictionary of available API endpoints
|
||||||
|
returned: success
|
||||||
|
type: dict
|
||||||
|
'''
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec()
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
module.exit_json(
|
||||||
|
changed=False,
|
||||||
|
ansible_facts=dict(
|
||||||
|
auth_token=cloud.auth_token,
|
||||||
|
service_catalog=cloud.service_catalog))
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
152
plugins/modules/baremetal_inspect.py
Normal file
152
plugins/modules/baremetal_inspect.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# coding: utf-8 -*-
|
||||||
|
|
||||||
|
# (c) 2015-2016, Hewlett Packard Enterprise Development Company LP
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: baremetal_inspect
|
||||||
|
short_description: Explicitly triggers baremetal node introspection in ironic.
|
||||||
|
author: "Julia Kreger (@juliakreger)"
|
||||||
|
description:
|
||||||
|
- Requests Ironic to set a node into inspect state in order to collect metadata regarding the node.
|
||||||
|
This command may be out of band or in-band depending on the ironic driver configuration.
|
||||||
|
This is only possible on nodes in 'manageable' and 'available' state.
|
||||||
|
options:
|
||||||
|
mac:
|
||||||
|
description:
|
||||||
|
- unique mac address that is used to attempt to identify the host.
|
||||||
|
type: str
|
||||||
|
uuid:
|
||||||
|
description:
|
||||||
|
- globally unique identifier (UUID) to identify the host.
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- unique name identifier to identify the host in Ironic.
|
||||||
|
type: str
|
||||||
|
ironic_url:
|
||||||
|
description:
|
||||||
|
- If noauth mode is utilized, this is required to be set to the endpoint URL for the Ironic API.
|
||||||
|
Use with "auth" and "auth_type" settings set to None.
|
||||||
|
type: str
|
||||||
|
timeout:
|
||||||
|
description:
|
||||||
|
- A timeout in seconds to tell the role to wait for the node to complete introspection if wait is set to True.
|
||||||
|
default: 1200
|
||||||
|
type: int
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
ansible_facts:
|
||||||
|
description: Dictionary of new facts representing discovered properties of the node..
|
||||||
|
returned: changed
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
memory_mb:
|
||||||
|
description: Amount of node memory as updated in the node properties
|
||||||
|
type: str
|
||||||
|
sample: "1024"
|
||||||
|
cpu_arch:
|
||||||
|
description: Detected CPU architecture type
|
||||||
|
type: str
|
||||||
|
sample: "x86_64"
|
||||||
|
local_gb:
|
||||||
|
description: Total size of local disk storage as updated in node properties.
|
||||||
|
type: str
|
||||||
|
sample: "10"
|
||||||
|
cpus:
|
||||||
|
description: Count of cpu cores defined in the updated node properties.
|
||||||
|
type: str
|
||||||
|
sample: "1"
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Invoke node inspection
|
||||||
|
- openstack.cloud.baremetal_inspect:
|
||||||
|
name: "testnode1"
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _choose_id_value(module):
|
||||||
|
if module.params['uuid']:
|
||||||
|
return module.params['uuid']
|
||||||
|
if module.params['name']:
|
||||||
|
return module.params['name']
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
auth_type=dict(required=False),
|
||||||
|
uuid=dict(required=False),
|
||||||
|
name=dict(required=False),
|
||||||
|
mac=dict(required=False),
|
||||||
|
ironic_url=dict(required=False),
|
||||||
|
timeout=dict(default=1200, type='int', required=False),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
if (
|
||||||
|
module.params['auth_type'] in [None, 'None']
|
||||||
|
and module.params['ironic_url'] is None
|
||||||
|
):
|
||||||
|
module.fail_json(msg="Authentication appears to be disabled, "
|
||||||
|
"Please define an ironic_url parameter")
|
||||||
|
|
||||||
|
if (
|
||||||
|
module.params['ironic_url']
|
||||||
|
and module.params['auth_type'] in [None, 'None']
|
||||||
|
):
|
||||||
|
module.params['auth'] = dict(
|
||||||
|
endpoint=module.params['ironic_url']
|
||||||
|
)
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
if module.params['name'] or module.params['uuid']:
|
||||||
|
server = cloud.get_machine(_choose_id_value(module))
|
||||||
|
elif module.params['mac']:
|
||||||
|
server = cloud.get_machine_by_mac(module.params['mac'])
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="The worlds did not align, "
|
||||||
|
"the host was not found as "
|
||||||
|
"no name, uuid, or mac was "
|
||||||
|
"defined.")
|
||||||
|
if server:
|
||||||
|
cloud.inspect_machine(server['uuid'], module.params['wait'])
|
||||||
|
# TODO(TheJulia): diff properties, ?and ports? and determine
|
||||||
|
# if a change occurred. In theory, the node is always changed
|
||||||
|
# if introspection is able to update the record.
|
||||||
|
module.exit_json(changed=True,
|
||||||
|
ansible_facts=server['properties'])
|
||||||
|
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="node not found.")
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
380
plugins/modules/baremetal_node.py
Normal file
380
plugins/modules/baremetal_node.py
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# coding: utf-8 -*-
|
||||||
|
|
||||||
|
# (c) 2014, Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: baremetal_node
|
||||||
|
short_description: Create/Delete Bare Metal Resources from OpenStack
|
||||||
|
author: "Monty Taylor (@emonty)"
|
||||||
|
description:
|
||||||
|
- Create or Remove Ironic nodes from OpenStack.
|
||||||
|
options:
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Indicates desired state of the resource
|
||||||
|
choices: ['present', 'absent']
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
uuid:
|
||||||
|
description:
|
||||||
|
- globally unique identifier (UUID) to be given to the resource. Will
|
||||||
|
be auto-generated if not specified, and name is specified.
|
||||||
|
- Definition of a UUID will always take precedence to a name value.
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- unique name identifier to be given to the resource.
|
||||||
|
type: str
|
||||||
|
driver:
|
||||||
|
description:
|
||||||
|
- The name of the Ironic Driver to use with this node.
|
||||||
|
- Required when I(state=present)
|
||||||
|
type: str
|
||||||
|
chassis_uuid:
|
||||||
|
description:
|
||||||
|
- Associate the node with a pre-defined chassis.
|
||||||
|
type: str
|
||||||
|
ironic_url:
|
||||||
|
description:
|
||||||
|
- If noauth mode is utilized, this is required to be set to the
|
||||||
|
endpoint URL for the Ironic API. Use with "auth" and "auth_type"
|
||||||
|
settings set to None.
|
||||||
|
type: str
|
||||||
|
driver_info:
|
||||||
|
description:
|
||||||
|
- Information for this server's driver. Will vary based on which
|
||||||
|
driver is in use. Any sub-field which is populated will be validated
|
||||||
|
during creation.
|
||||||
|
required: true
|
||||||
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
power:
|
||||||
|
description:
|
||||||
|
- Information necessary to turn this server on / off.
|
||||||
|
This often includes such things as IPMI username, password, and IP address.
|
||||||
|
required: true
|
||||||
|
deploy:
|
||||||
|
description:
|
||||||
|
- Information necessary to deploy this server directly, without using Nova. THIS IS NOT RECOMMENDED.
|
||||||
|
console:
|
||||||
|
description:
|
||||||
|
- Information necessary to connect to this server's serial console. Not all drivers support this.
|
||||||
|
management:
|
||||||
|
description:
|
||||||
|
- Information necessary to interact with this server's management interface. May be shared by power_info in some cases.
|
||||||
|
required: true
|
||||||
|
nics:
|
||||||
|
description:
|
||||||
|
- 'A list of network interface cards, eg, " - mac: aa:bb:cc:aa:bb:cc"'
|
||||||
|
required: true
|
||||||
|
type: list
|
||||||
|
elements: dict
|
||||||
|
suboptions:
|
||||||
|
mac:
|
||||||
|
description: The MAC address of the network interface card.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
properties:
|
||||||
|
description:
|
||||||
|
- Definition of the physical characteristics of this server, used for scheduling purposes
|
||||||
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
cpu_arch:
|
||||||
|
description:
|
||||||
|
- CPU architecture (x86_64, i686, ...)
|
||||||
|
default: x86_64
|
||||||
|
cpus:
|
||||||
|
description:
|
||||||
|
- Number of CPU cores this machine has
|
||||||
|
default: 1
|
||||||
|
ram:
|
||||||
|
description:
|
||||||
|
- amount of RAM this machine has, in MB
|
||||||
|
default: 1
|
||||||
|
disk_size:
|
||||||
|
description:
|
||||||
|
- size of first storage device in this machine (typically /dev/sda), in GB
|
||||||
|
default: 1
|
||||||
|
capabilities:
|
||||||
|
description:
|
||||||
|
- special capabilities for the node, such as boot_option, node_role etc
|
||||||
|
(see U(https://docs.openstack.org/ironic/latest/install/advanced.html)
|
||||||
|
for more information)
|
||||||
|
default: ""
|
||||||
|
root_device:
|
||||||
|
description:
|
||||||
|
- Root disk device hints for deployment.
|
||||||
|
- See U(https://docs.openstack.org/ironic/latest/install/advanced.html#specifying-the-disk-for-deployment-root-device-hints)
|
||||||
|
for allowed hints.
|
||||||
|
default: ""
|
||||||
|
skip_update_of_masked_password:
|
||||||
|
description:
|
||||||
|
- Allows the code that would assert changes to nodes to skip the
|
||||||
|
update if the change is a single line consisting of the password
|
||||||
|
field.
|
||||||
|
- As of Kilo, by default, passwords are always masked to API
|
||||||
|
requests, which means the logic as a result always attempts to
|
||||||
|
re-assert the password field.
|
||||||
|
- C(skip_update_of_driver_password) is deprecated alias and will be removed in 2.14.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
aliases: [ skip_update_of_driver_password ]
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
- "jsonpatch"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Enroll a node with some basic properties and driver info
|
||||||
|
- openstack.cloud.baremetal_node:
|
||||||
|
cloud: "devstack"
|
||||||
|
driver: "pxe_ipmitool"
|
||||||
|
uuid: "00000000-0000-0000-0000-000000000002"
|
||||||
|
properties:
|
||||||
|
cpus: 2
|
||||||
|
cpu_arch: "x86_64"
|
||||||
|
ram: 8192
|
||||||
|
disk_size: 64
|
||||||
|
capabilities: "boot_option:local"
|
||||||
|
root_device:
|
||||||
|
wwn: "0x4000cca77fc4dba1"
|
||||||
|
nics:
|
||||||
|
- mac: "aa:bb:cc:aa:bb:cc"
|
||||||
|
- mac: "dd:ee:ff:dd:ee:ff"
|
||||||
|
driver_info:
|
||||||
|
power:
|
||||||
|
ipmi_address: "1.2.3.4"
|
||||||
|
ipmi_username: "admin"
|
||||||
|
ipmi_password: "adminpass"
|
||||||
|
chassis_uuid: "00000000-0000-0000-0000-000000000001"
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
try:
|
||||||
|
import jsonpatch
|
||||||
|
HAS_JSONPATCH = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_JSONPATCH = False
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_properties(module):
|
||||||
|
p = module.params['properties']
|
||||||
|
props = dict(
|
||||||
|
cpu_arch=p.get('cpu_arch') if p.get('cpu_arch') else 'x86_64',
|
||||||
|
cpus=p.get('cpus') if p.get('cpus') else 1,
|
||||||
|
memory_mb=p.get('ram') if p.get('ram') else 1,
|
||||||
|
local_gb=p.get('disk_size') if p.get('disk_size') else 1,
|
||||||
|
capabilities=p.get('capabilities') if p.get('capabilities') else '',
|
||||||
|
root_device=p.get('root_device') if p.get('root_device') else '',
|
||||||
|
)
|
||||||
|
return props
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_driver_info(sdk, module):
|
||||||
|
p = module.params['driver_info']
|
||||||
|
info = p.get('power')
|
||||||
|
if not info:
|
||||||
|
raise sdk.exceptions.OpenStackCloudException(
|
||||||
|
"driver_info['power'] is required")
|
||||||
|
if p.get('console'):
|
||||||
|
info.update(p.get('console'))
|
||||||
|
if p.get('management'):
|
||||||
|
info.update(p.get('management'))
|
||||||
|
if p.get('deploy'):
|
||||||
|
info.update(p.get('deploy'))
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
def _choose_id_value(module):
|
||||||
|
if module.params['uuid']:
|
||||||
|
return module.params['uuid']
|
||||||
|
if module.params['name']:
|
||||||
|
return module.params['name']
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _choose_if_password_only(module, patch):
|
||||||
|
if len(patch) == 1:
|
||||||
|
if 'password' in patch[0]['path'] and module.params['skip_update_of_masked_password']:
|
||||||
|
# Return false to abort update as the password appears
|
||||||
|
# to be the only element in the patch.
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _exit_node_not_updated(module, server):
|
||||||
|
module.exit_json(
|
||||||
|
changed=False,
|
||||||
|
result="Node not updated",
|
||||||
|
uuid=server['uuid'],
|
||||||
|
provision_state=server['provision_state']
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
uuid=dict(required=False),
|
||||||
|
name=dict(required=False),
|
||||||
|
driver=dict(required=False),
|
||||||
|
driver_info=dict(type='dict', required=True),
|
||||||
|
nics=dict(type='list', required=True, elements="dict"),
|
||||||
|
properties=dict(type='dict', default={}),
|
||||||
|
ironic_url=dict(required=False),
|
||||||
|
chassis_uuid=dict(required=False),
|
||||||
|
skip_update_of_masked_password=dict(
|
||||||
|
required=False,
|
||||||
|
type='bool',
|
||||||
|
aliases=['skip_update_of_driver_password'],
|
||||||
|
deprecated_aliases=[dict(name='skip_update_of_driver_password', version='2.14')]
|
||||||
|
),
|
||||||
|
state=dict(required=False, default='present', choices=['present', 'absent'])
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
if not HAS_JSONPATCH:
|
||||||
|
module.fail_json(msg='jsonpatch is required for this module')
|
||||||
|
if (
|
||||||
|
module.params['auth_type'] in [None, 'None']
|
||||||
|
and module.params['ironic_url'] is None
|
||||||
|
):
|
||||||
|
module.fail_json(msg="Authentication appears to be disabled, "
|
||||||
|
"Please define an ironic_url parameter")
|
||||||
|
|
||||||
|
if (
|
||||||
|
module.params['ironic_url']
|
||||||
|
and module.params['auth_type'] in [None, 'None']
|
||||||
|
):
|
||||||
|
module.params['auth'] = dict(
|
||||||
|
endpoint=module.params['ironic_url']
|
||||||
|
)
|
||||||
|
|
||||||
|
node_id = _choose_id_value(module)
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
server = cloud.get_machine(node_id)
|
||||||
|
if module.params['state'] == 'present':
|
||||||
|
if module.params['driver'] is None:
|
||||||
|
module.fail_json(msg="A driver must be defined in order "
|
||||||
|
"to set a node to present.")
|
||||||
|
|
||||||
|
properties = _parse_properties(module)
|
||||||
|
driver_info = _parse_driver_info(sdk, module)
|
||||||
|
kwargs = dict(
|
||||||
|
driver=module.params['driver'],
|
||||||
|
properties=properties,
|
||||||
|
driver_info=driver_info,
|
||||||
|
name=module.params['name'],
|
||||||
|
)
|
||||||
|
|
||||||
|
if module.params['chassis_uuid']:
|
||||||
|
kwargs['chassis_uuid'] = module.params['chassis_uuid']
|
||||||
|
|
||||||
|
if server is None:
|
||||||
|
# Note(TheJulia): Add a specific UUID to the request if
|
||||||
|
# present in order to be able to re-use kwargs for if
|
||||||
|
# the node already exists logic, since uuid cannot be
|
||||||
|
# updated.
|
||||||
|
if module.params['uuid']:
|
||||||
|
kwargs['uuid'] = module.params['uuid']
|
||||||
|
|
||||||
|
server = cloud.register_machine(module.params['nics'],
|
||||||
|
**kwargs)
|
||||||
|
module.exit_json(changed=True, uuid=server['uuid'],
|
||||||
|
provision_state=server['provision_state'])
|
||||||
|
else:
|
||||||
|
# TODO(TheJulia): Presently this does not support updating
|
||||||
|
# nics. Support needs to be added.
|
||||||
|
#
|
||||||
|
# Note(TheJulia): This message should never get logged
|
||||||
|
# however we cannot realistically proceed if neither a
|
||||||
|
# name or uuid was supplied to begin with.
|
||||||
|
if not node_id:
|
||||||
|
module.fail_json(msg="A uuid or name value "
|
||||||
|
"must be defined")
|
||||||
|
|
||||||
|
# Note(TheJulia): Constructing the configuration to compare
|
||||||
|
# against. The items listed in the server_config block can
|
||||||
|
# be updated via the API.
|
||||||
|
|
||||||
|
server_config = dict(
|
||||||
|
driver=server['driver'],
|
||||||
|
properties=server['properties'],
|
||||||
|
driver_info=server['driver_info'],
|
||||||
|
name=server['name'],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the pre-existing chassis_uuid only if
|
||||||
|
# it is present in the server configuration.
|
||||||
|
if hasattr(server, 'chassis_uuid'):
|
||||||
|
server_config['chassis_uuid'] = server['chassis_uuid']
|
||||||
|
|
||||||
|
# Note(TheJulia): If a password is defined and concealed, a
|
||||||
|
# patch will always be generated and re-asserted.
|
||||||
|
patch = jsonpatch.JsonPatch.from_diff(server_config, kwargs)
|
||||||
|
|
||||||
|
if not patch:
|
||||||
|
_exit_node_not_updated(module, server)
|
||||||
|
elif _choose_if_password_only(module, list(patch)):
|
||||||
|
# Note(TheJulia): Normally we would allow the general
|
||||||
|
# exception catch below, however this allows a specific
|
||||||
|
# message.
|
||||||
|
try:
|
||||||
|
server = cloud.patch_machine(
|
||||||
|
server['uuid'],
|
||||||
|
list(patch))
|
||||||
|
except Exception as e:
|
||||||
|
module.fail_json(msg="Failed to update node, "
|
||||||
|
"Error: %s" % e.message)
|
||||||
|
|
||||||
|
# Enumerate out a list of changed paths.
|
||||||
|
change_list = []
|
||||||
|
for change in list(patch):
|
||||||
|
change_list.append(change['path'])
|
||||||
|
module.exit_json(changed=True,
|
||||||
|
result="Node Updated",
|
||||||
|
changes=change_list,
|
||||||
|
uuid=server['uuid'],
|
||||||
|
provision_state=server['provision_state'])
|
||||||
|
|
||||||
|
# Return not updated by default as the conditions were not met
|
||||||
|
# to update.
|
||||||
|
_exit_node_not_updated(module, server)
|
||||||
|
|
||||||
|
if module.params['state'] == 'absent':
|
||||||
|
if not node_id:
|
||||||
|
module.fail_json(msg="A uuid or name value must be defined "
|
||||||
|
"in order to remove a node.")
|
||||||
|
|
||||||
|
if server is not None:
|
||||||
|
cloud.unregister_machine(module.params['nics'],
|
||||||
|
server['uuid'])
|
||||||
|
module.exit_json(changed=True, result="deleted")
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, result="Server not found")
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
379
plugins/modules/baremetal_node_action.py
Normal file
379
plugins/modules/baremetal_node_action.py
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# coding: utf-8 -*-
|
||||||
|
|
||||||
|
# (c) 2015, Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: baremetal_node_action
|
||||||
|
short_description: Activate/Deactivate Bare Metal Resources from OpenStack
|
||||||
|
author: "Monty Taylor (@emonty)"
|
||||||
|
description:
|
||||||
|
- Deploy to nodes controlled by Ironic.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the node to create.
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Indicates desired state of the resource.
|
||||||
|
- I(state) can be C('present'), C('absent'), C('maintenance') or C('off').
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
deploy:
|
||||||
|
description:
|
||||||
|
- Indicates if the resource should be deployed. Allows for deployment
|
||||||
|
logic to be disengaged and control of the node power or maintenance
|
||||||
|
state to be changed.
|
||||||
|
type: str
|
||||||
|
default: 'yes'
|
||||||
|
uuid:
|
||||||
|
description:
|
||||||
|
- globally unique identifier (UUID) to be given to the resource.
|
||||||
|
type: str
|
||||||
|
ironic_url:
|
||||||
|
description:
|
||||||
|
- If noauth mode is utilized, this is required to be set to the
|
||||||
|
endpoint URL for the Ironic API. Use with "auth" and "auth_type"
|
||||||
|
settings set to None.
|
||||||
|
type: str
|
||||||
|
config_drive:
|
||||||
|
description:
|
||||||
|
- A configdrive file or HTTP(S) URL that will be passed along to the
|
||||||
|
node.
|
||||||
|
type: raw
|
||||||
|
instance_info:
|
||||||
|
description:
|
||||||
|
- Definition of the instance information which is used to deploy
|
||||||
|
the node. This information is only required when an instance is
|
||||||
|
set to present.
|
||||||
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
image_source:
|
||||||
|
description:
|
||||||
|
- An HTTP(S) URL where the image can be retrieved from.
|
||||||
|
image_checksum:
|
||||||
|
description:
|
||||||
|
- The checksum of image_source.
|
||||||
|
image_disk_format:
|
||||||
|
description:
|
||||||
|
- The type of image that has been requested to be deployed.
|
||||||
|
power:
|
||||||
|
description:
|
||||||
|
- A setting to allow power state to be asserted allowing nodes
|
||||||
|
that are not yet deployed to be powered on, and nodes that
|
||||||
|
are deployed to be powered off.
|
||||||
|
- I(power) can be C('present'), C('absent'), C('maintenance') or C('off').
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
maintenance:
|
||||||
|
description:
|
||||||
|
- A setting to allow the direct control if a node is in
|
||||||
|
maintenance mode.
|
||||||
|
- I(maintenance) can be C('yes'), C('no'), C('True'), or C('False').
|
||||||
|
type: str
|
||||||
|
maintenance_reason:
|
||||||
|
description:
|
||||||
|
- A string expression regarding the reason a node is in a
|
||||||
|
maintenance mode.
|
||||||
|
type: str
|
||||||
|
wait:
|
||||||
|
description:
|
||||||
|
- A boolean value instructing the module to wait for node
|
||||||
|
activation or deactivation to complete before returning.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
timeout:
|
||||||
|
description:
|
||||||
|
- An integer value representing the number of seconds to
|
||||||
|
wait for the node activation or deactivation to complete.
|
||||||
|
default: 1800
|
||||||
|
type: int
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Activate a node by booting an image with a configdrive attached
|
||||||
|
- openstack.cloud.baremetal_node_action:
|
||||||
|
cloud: "openstack"
|
||||||
|
uuid: "d44666e1-35b3-4f6b-acb0-88ab7052da69"
|
||||||
|
state: present
|
||||||
|
power: present
|
||||||
|
deploy: True
|
||||||
|
maintenance: False
|
||||||
|
config_drive: "http://192.168.1.1/host-configdrive.iso"
|
||||||
|
instance_info:
|
||||||
|
image_source: "http://192.168.1.1/deploy_image.img"
|
||||||
|
image_checksum: "356a6b55ecc511a20c33c946c4e678af"
|
||||||
|
image_disk_format: "qcow"
|
||||||
|
delegate_to: localhost
|
||||||
|
|
||||||
|
# Activate a node by booting an image with a configdrive json object
|
||||||
|
- openstack.cloud.baremetal_node_action:
|
||||||
|
uuid: "d44666e1-35b3-4f6b-acb0-88ab7052da69"
|
||||||
|
auth_type: None
|
||||||
|
ironic_url: "http://192.168.1.1:6385/"
|
||||||
|
config_drive:
|
||||||
|
meta_data:
|
||||||
|
hostname: node1
|
||||||
|
public_keys:
|
||||||
|
default: ssh-rsa AAA...BBB==
|
||||||
|
instance_info:
|
||||||
|
image_source: "http://192.168.1.1/deploy_image.img"
|
||||||
|
image_checksum: "356a6b55ecc511a20c33c946c4e678af"
|
||||||
|
image_disk_format: "qcow"
|
||||||
|
delegate_to: localhost
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _choose_id_value(module):
|
||||||
|
if module.params['uuid']:
|
||||||
|
return module.params['uuid']
|
||||||
|
if module.params['name']:
|
||||||
|
return module.params['name']
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _is_true(value):
|
||||||
|
true_values = [True, 'yes', 'Yes', 'True', 'true', 'present', 'on']
|
||||||
|
if value in true_values:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _is_false(value):
|
||||||
|
false_values = [False, None, 'no', 'No', 'False', 'false', 'absent', 'off']
|
||||||
|
if value in false_values:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _check_set_maintenance(module, cloud, node):
|
||||||
|
if _is_true(module.params['maintenance']):
|
||||||
|
if _is_false(node['maintenance']):
|
||||||
|
cloud.set_machine_maintenance_state(
|
||||||
|
node['uuid'],
|
||||||
|
True,
|
||||||
|
reason=module.params['maintenance_reason'])
|
||||||
|
module.exit_json(changed=True, msg="Node has been set into "
|
||||||
|
"maintenance mode")
|
||||||
|
else:
|
||||||
|
# User has requested maintenance state, node is already in the
|
||||||
|
# desired state, checking to see if the reason has changed.
|
||||||
|
if (str(node['maintenance_reason']) not in
|
||||||
|
str(module.params['maintenance_reason'])):
|
||||||
|
cloud.set_machine_maintenance_state(
|
||||||
|
node['uuid'],
|
||||||
|
True,
|
||||||
|
reason=module.params['maintenance_reason'])
|
||||||
|
module.exit_json(changed=True, msg="Node maintenance reason "
|
||||||
|
"updated, cannot take any "
|
||||||
|
"additional action.")
|
||||||
|
elif _is_false(module.params['maintenance']):
|
||||||
|
if node['maintenance'] is True:
|
||||||
|
cloud.remove_machine_from_maintenance(node['uuid'])
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="maintenance parameter was set but a valid "
|
||||||
|
"the value was not recognized.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _check_set_power_state(module, cloud, node):
|
||||||
|
if 'power on' in str(node['power_state']):
|
||||||
|
if _is_false(module.params['power']):
|
||||||
|
# User has requested the node be powered off.
|
||||||
|
cloud.set_machine_power_off(node['uuid'])
|
||||||
|
module.exit_json(changed=True, msg="Power requested off")
|
||||||
|
if 'power off' in str(node['power_state']):
|
||||||
|
if (
|
||||||
|
_is_false(module.params['power'])
|
||||||
|
and _is_false(module.params['state'])
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
if (
|
||||||
|
_is_false(module.params['power'])
|
||||||
|
and _is_false(module.params['state'])
|
||||||
|
):
|
||||||
|
module.exit_json(
|
||||||
|
changed=False,
|
||||||
|
msg="Power for node is %s, node must be reactivated "
|
||||||
|
"OR set to state absent"
|
||||||
|
)
|
||||||
|
# In the event the power has been toggled on and
|
||||||
|
# deployment has been requested, we need to skip this
|
||||||
|
# step.
|
||||||
|
if (
|
||||||
|
_is_true(module.params['power'])
|
||||||
|
and _is_false(module.params['deploy'])
|
||||||
|
):
|
||||||
|
# Node is powered down when it is not awaiting to be provisioned
|
||||||
|
cloud.set_machine_power_on(node['uuid'])
|
||||||
|
return True
|
||||||
|
# Default False if no action has been taken.
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
uuid=dict(required=False),
|
||||||
|
name=dict(required=False),
|
||||||
|
instance_info=dict(type='dict', required=False),
|
||||||
|
config_drive=dict(type='raw', required=False),
|
||||||
|
ironic_url=dict(required=False),
|
||||||
|
state=dict(required=False, default='present'),
|
||||||
|
maintenance=dict(required=False),
|
||||||
|
maintenance_reason=dict(required=False),
|
||||||
|
power=dict(required=False, default='present'),
|
||||||
|
deploy=dict(required=False, default='yes'),
|
||||||
|
wait=dict(type='bool', required=False, default=False),
|
||||||
|
timeout=dict(required=False, type='int', default=1800),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
if (
|
||||||
|
module.params['auth_type'] in [None, 'None']
|
||||||
|
and module.params['ironic_url'] is None
|
||||||
|
):
|
||||||
|
module.fail_json(msg="Authentication appears disabled, Please "
|
||||||
|
"define an ironic_url parameter")
|
||||||
|
|
||||||
|
if (
|
||||||
|
module.params['ironic_url']
|
||||||
|
and module.params['auth_type'] in [None, 'None']
|
||||||
|
):
|
||||||
|
module.params['auth'] = dict(
|
||||||
|
endpoint=module.params['ironic_url']
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
module.params['config_drive']
|
||||||
|
and not isinstance(module.params['config_drive'], (str, dict))
|
||||||
|
):
|
||||||
|
config_drive_type = type(module.params['config_drive'])
|
||||||
|
msg = ('argument config_drive is of type %s and we expected'
|
||||||
|
' str or dict') % config_drive_type
|
||||||
|
module.fail_json(msg=msg)
|
||||||
|
|
||||||
|
node_id = _choose_id_value(module)
|
||||||
|
|
||||||
|
if not node_id:
|
||||||
|
module.fail_json(msg="A uuid or name value must be defined "
|
||||||
|
"to use this module.")
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
node = cloud.get_machine(node_id)
|
||||||
|
|
||||||
|
if node is None:
|
||||||
|
module.fail_json(msg="node not found")
|
||||||
|
|
||||||
|
uuid = node['uuid']
|
||||||
|
instance_info = module.params['instance_info']
|
||||||
|
changed = False
|
||||||
|
wait = module.params['wait']
|
||||||
|
timeout = module.params['timeout']
|
||||||
|
|
||||||
|
# User has requested desired state to be in maintenance state.
|
||||||
|
if module.params['state'] == 'maintenance':
|
||||||
|
module.params['maintenance'] = True
|
||||||
|
|
||||||
|
if node['provision_state'] in [
|
||||||
|
'cleaning',
|
||||||
|
'deleting',
|
||||||
|
'wait call-back']:
|
||||||
|
module.fail_json(msg="Node is in %s state, cannot act upon the "
|
||||||
|
"request as the node is in a transition "
|
||||||
|
"state" % node['provision_state'])
|
||||||
|
# TODO(TheJulia) This is in-development code, that requires
|
||||||
|
# code in the shade library that is still in development.
|
||||||
|
if _check_set_maintenance(module, cloud, node):
|
||||||
|
if node['provision_state'] in 'active':
|
||||||
|
module.exit_json(changed=True,
|
||||||
|
result="Maintenance state changed")
|
||||||
|
changed = True
|
||||||
|
node = cloud.get_machine(node_id)
|
||||||
|
|
||||||
|
if _check_set_power_state(module, cloud, node):
|
||||||
|
changed = True
|
||||||
|
node = cloud.get_machine(node_id)
|
||||||
|
|
||||||
|
if _is_true(module.params['state']):
|
||||||
|
if _is_false(module.params['deploy']):
|
||||||
|
module.exit_json(
|
||||||
|
changed=changed,
|
||||||
|
result="User request has explicitly disabled "
|
||||||
|
"deployment logic"
|
||||||
|
)
|
||||||
|
|
||||||
|
if 'active' in node['provision_state']:
|
||||||
|
module.exit_json(
|
||||||
|
changed=changed,
|
||||||
|
result="Node already in an active state."
|
||||||
|
)
|
||||||
|
|
||||||
|
if instance_info is None:
|
||||||
|
module.fail_json(
|
||||||
|
changed=changed,
|
||||||
|
msg="When setting an instance to present, "
|
||||||
|
"instance_info is a required variable.")
|
||||||
|
|
||||||
|
# TODO(TheJulia): Update instance info, however info is
|
||||||
|
# deployment specific. Perhaps consider adding rebuild
|
||||||
|
# support, although there is a known desire to remove
|
||||||
|
# rebuild support from Ironic at some point in the future.
|
||||||
|
cloud.update_machine(uuid, instance_info=instance_info)
|
||||||
|
cloud.validate_node(uuid)
|
||||||
|
if not wait:
|
||||||
|
cloud.activate_node(uuid, module.params['config_drive'])
|
||||||
|
else:
|
||||||
|
cloud.activate_node(
|
||||||
|
uuid,
|
||||||
|
configdrive=module.params['config_drive'],
|
||||||
|
wait=wait,
|
||||||
|
timeout=timeout)
|
||||||
|
# TODO(TheJulia): Add more error checking..
|
||||||
|
module.exit_json(changed=changed, result="node activated")
|
||||||
|
|
||||||
|
elif _is_false(module.params['state']):
|
||||||
|
if node['provision_state'] not in "deleted":
|
||||||
|
cloud.update_machine(uuid, instance_info={})
|
||||||
|
if not wait:
|
||||||
|
cloud.deactivate_node(uuid)
|
||||||
|
else:
|
||||||
|
cloud.deactivate_node(
|
||||||
|
uuid,
|
||||||
|
wait=wait,
|
||||||
|
timeout=timeout)
|
||||||
|
|
||||||
|
module.exit_json(changed=True, result="deleted")
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, result="node not found")
|
||||||
|
else:
|
||||||
|
module.fail_json(msg="State must be present, absent, "
|
||||||
|
"maintenance, off")
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
195
plugins/modules/catalog_service.py
Normal file
195
plugins/modules/catalog_service.py
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright 2016 Sam Yaple
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: catalog_service
|
||||||
|
short_description: Manage OpenStack Identity services
|
||||||
|
author: "Sam Yaple (@SamYaple)"
|
||||||
|
description:
|
||||||
|
- Create, update, or delete OpenStack Identity service. If a service
|
||||||
|
with the supplied name already exists, it will be updated with the
|
||||||
|
new description and enabled attributes.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name of the service
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
description:
|
||||||
|
- Description of the service
|
||||||
|
type: str
|
||||||
|
enabled:
|
||||||
|
description:
|
||||||
|
- Is the service enabled
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
service_type:
|
||||||
|
description:
|
||||||
|
- The type of service
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a service for glance
|
||||||
|
- openstack.cloud.catalog_service:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: glance
|
||||||
|
service_type: image
|
||||||
|
description: OpenStack Image Service
|
||||||
|
# Delete a service
|
||||||
|
- openstack.cloud.catalog_service:
|
||||||
|
cloud: mycloud
|
||||||
|
state: absent
|
||||||
|
name: glance
|
||||||
|
service_type: image
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
service:
|
||||||
|
description: Dictionary describing the service.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Service ID.
|
||||||
|
type: str
|
||||||
|
sample: "3292f020780b4d5baf27ff7e1d224c44"
|
||||||
|
name:
|
||||||
|
description: Service name.
|
||||||
|
type: str
|
||||||
|
sample: "glance"
|
||||||
|
service_type:
|
||||||
|
description: Service type.
|
||||||
|
type: str
|
||||||
|
sample: "image"
|
||||||
|
description:
|
||||||
|
description: Service description.
|
||||||
|
type: str
|
||||||
|
sample: "OpenStack Image Service"
|
||||||
|
enabled:
|
||||||
|
description: Service status.
|
||||||
|
type: bool
|
||||||
|
sample: True
|
||||||
|
id:
|
||||||
|
description: The service ID.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: str
|
||||||
|
sample: "3292f020780b4d5baf27ff7e1d224c44"
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _needs_update(module, service):
|
||||||
|
if service.enabled != module.params['enabled']:
|
||||||
|
return True
|
||||||
|
if service.description is not None and \
|
||||||
|
service.description != module.params['description']:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(module, service):
|
||||||
|
state = module.params['state']
|
||||||
|
if state == 'absent' and service:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if service is None:
|
||||||
|
return True
|
||||||
|
return _needs_update(module, service)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
description=dict(default=None),
|
||||||
|
enabled=dict(default=True, type='bool'),
|
||||||
|
name=dict(required=True),
|
||||||
|
service_type=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
description = module.params['description']
|
||||||
|
enabled = module.params['enabled']
|
||||||
|
name = module.params['name']
|
||||||
|
state = module.params['state']
|
||||||
|
service_type = module.params['service_type']
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
services = cloud.search_services(name_or_id=name,
|
||||||
|
filters=dict(type=service_type))
|
||||||
|
|
||||||
|
if len(services) > 1:
|
||||||
|
module.fail_json(msg='Service name %s and type %s are not unique' %
|
||||||
|
(name, service_type))
|
||||||
|
elif len(services) == 1:
|
||||||
|
service = services[0]
|
||||||
|
else:
|
||||||
|
service = None
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(module, service))
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if service is None:
|
||||||
|
service = cloud.create_service(name=name, description=description,
|
||||||
|
type=service_type, enabled=True)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
if _needs_update(module, service):
|
||||||
|
service = cloud.update_service(
|
||||||
|
service.id, name=name, type=service_type, enabled=enabled,
|
||||||
|
description=description)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
module.exit_json(changed=changed, service=service, id=service.id)
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if service is None:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
cloud.delete_service(service.id)
|
||||||
|
changed = True
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
299
plugins/modules/coe_cluster.py
Normal file
299
plugins/modules/coe_cluster.py
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2018 Catalyst IT Ltd.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: coe_cluster
|
||||||
|
short_description: Add/Remove COE cluster from OpenStack Cloud
|
||||||
|
author: "Feilong Wang (@flwang)"
|
||||||
|
description:
|
||||||
|
- Add or Remove COE cluster from the OpenStack Container Infra service.
|
||||||
|
options:
|
||||||
|
cluster_template_id:
|
||||||
|
description:
|
||||||
|
- The template ID of cluster template.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
discovery_url:
|
||||||
|
description:
|
||||||
|
- Url used for cluster node discovery
|
||||||
|
type: str
|
||||||
|
docker_volume_size:
|
||||||
|
description:
|
||||||
|
- The size in GB of the docker volume
|
||||||
|
type: int
|
||||||
|
flavor_id:
|
||||||
|
description:
|
||||||
|
- The flavor of the minion node for this ClusterTemplate
|
||||||
|
type: str
|
||||||
|
keypair:
|
||||||
|
description:
|
||||||
|
- Name of the keypair to use.
|
||||||
|
type: str
|
||||||
|
labels:
|
||||||
|
description:
|
||||||
|
- One or more key/value pairs
|
||||||
|
type: raw
|
||||||
|
master_flavor_id:
|
||||||
|
description:
|
||||||
|
- The flavor of the master node for this ClusterTemplate
|
||||||
|
type: str
|
||||||
|
master_count:
|
||||||
|
description:
|
||||||
|
- The number of master nodes for this cluster
|
||||||
|
default: 1
|
||||||
|
type: int
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the cluster template
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
node_count:
|
||||||
|
description:
|
||||||
|
- The number of nodes for this cluster
|
||||||
|
default: 1
|
||||||
|
type: int
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Indicate desired state of the resource.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
timeout:
|
||||||
|
description:
|
||||||
|
- Timeout for creating the cluster in minutes. Default to 60 mins
|
||||||
|
if not set
|
||||||
|
default: 60
|
||||||
|
type: int
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
id:
|
||||||
|
description: The cluster UUID.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
cluster:
|
||||||
|
description: Dictionary describing the cluster.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
api_address:
|
||||||
|
description:
|
||||||
|
- Api address of cluster master node
|
||||||
|
type: str
|
||||||
|
sample: https://172.24.4.30:6443
|
||||||
|
cluster_template_id:
|
||||||
|
description: The cluster_template UUID
|
||||||
|
type: str
|
||||||
|
sample: '7b1418c8-cea8-48fc-995d-52b66af9a9aa'
|
||||||
|
coe_version:
|
||||||
|
description:
|
||||||
|
- Version of the COE software currently running in this cluster
|
||||||
|
type: str
|
||||||
|
sample: v1.11.1
|
||||||
|
container_version:
|
||||||
|
description:
|
||||||
|
- "Version of the container software. Example: docker version."
|
||||||
|
type: str
|
||||||
|
sample: 1.12.6
|
||||||
|
created_at:
|
||||||
|
description:
|
||||||
|
- The time in UTC at which the cluster is created
|
||||||
|
type: str
|
||||||
|
sample: "2018-08-16T10:29:45+00:00"
|
||||||
|
create_timeout:
|
||||||
|
description:
|
||||||
|
- Timeout for creating the cluster in minutes. Default to 60 if
|
||||||
|
not set.
|
||||||
|
type: int
|
||||||
|
sample: 60
|
||||||
|
discovery_url:
|
||||||
|
description:
|
||||||
|
- Url used for cluster node discovery
|
||||||
|
type: str
|
||||||
|
sample: https://discovery.etcd.io/a42ee38e7113f31f4d6324f24367aae5
|
||||||
|
faults:
|
||||||
|
description:
|
||||||
|
- Fault info collected from the Heat resources of this cluster
|
||||||
|
type: dict
|
||||||
|
sample: {'0': 'ResourceInError: resources[0].resources...'}
|
||||||
|
flavor_id:
|
||||||
|
description:
|
||||||
|
- The flavor of the minion node for this cluster
|
||||||
|
type: str
|
||||||
|
sample: c1.c1r1
|
||||||
|
keypair:
|
||||||
|
description:
|
||||||
|
- Name of the keypair to use.
|
||||||
|
type: str
|
||||||
|
sample: mykey
|
||||||
|
labels:
|
||||||
|
description: One or more key/value pairs
|
||||||
|
type: dict
|
||||||
|
sample: {'key1': 'value1', 'key2': 'value2'}
|
||||||
|
master_addresses:
|
||||||
|
description:
|
||||||
|
- IP addresses of cluster master nodes
|
||||||
|
type: list
|
||||||
|
sample: ['172.24.4.5']
|
||||||
|
master_count:
|
||||||
|
description:
|
||||||
|
- The number of master nodes for this cluster.
|
||||||
|
type: int
|
||||||
|
sample: 1
|
||||||
|
master_flavor_id:
|
||||||
|
description:
|
||||||
|
- The flavor of the master node for this cluster
|
||||||
|
type: str
|
||||||
|
sample: c1.c1r1
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the cluster
|
||||||
|
type: str
|
||||||
|
sample: k8scluster
|
||||||
|
node_addresses:
|
||||||
|
description:
|
||||||
|
- IP addresses of cluster slave nodes
|
||||||
|
type: list
|
||||||
|
sample: ['172.24.4.8']
|
||||||
|
node_count:
|
||||||
|
description:
|
||||||
|
- The number of master nodes for this cluster.
|
||||||
|
type: int
|
||||||
|
sample: 1
|
||||||
|
stack_id:
|
||||||
|
description:
|
||||||
|
- Stack id of the Heat stack
|
||||||
|
type: str
|
||||||
|
sample: '07767ec6-85f5-44cb-bd63-242a8e7f0d9d'
|
||||||
|
status:
|
||||||
|
description: Status of the cluster from the heat stack
|
||||||
|
type: str
|
||||||
|
sample: 'CREATE_COMLETE'
|
||||||
|
status_reason:
|
||||||
|
description:
|
||||||
|
- Status reason of the cluster from the heat stack
|
||||||
|
type: str
|
||||||
|
sample: 'Stack CREATE completed successfully'
|
||||||
|
updated_at:
|
||||||
|
description:
|
||||||
|
- The time in UTC at which the cluster is updated
|
||||||
|
type: str
|
||||||
|
sample: '2018-08-16T10:39:25+00:00'
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- Unique UUID for this cluster
|
||||||
|
type: str
|
||||||
|
sample: '86246a4d-a16c-4a58-9e96ad7719fe0f9d'
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a new Kubernetes cluster
|
||||||
|
- openstack.cloud.coe_cluster:
|
||||||
|
name: k8s
|
||||||
|
cluster_template_id: k8s-ha
|
||||||
|
keypair: mykey
|
||||||
|
master_count: 3
|
||||||
|
node_count: 5
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_labels(labels):
|
||||||
|
if isinstance(labels, str):
|
||||||
|
labels_dict = {}
|
||||||
|
for kv_str in labels.split(","):
|
||||||
|
k, v = kv_str.split("=")
|
||||||
|
labels_dict[k] = v
|
||||||
|
return labels_dict
|
||||||
|
if not labels:
|
||||||
|
return {}
|
||||||
|
return labels
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
cluster_template_id=dict(required=True),
|
||||||
|
discovery_url=dict(default=None),
|
||||||
|
docker_volume_size=dict(type='int'),
|
||||||
|
flavor_id=dict(default=None),
|
||||||
|
keypair=dict(default=None),
|
||||||
|
labels=dict(default=None, type='raw'),
|
||||||
|
master_count=dict(type='int', default=1),
|
||||||
|
master_flavor_id=dict(default=None),
|
||||||
|
name=dict(required=True),
|
||||||
|
node_count=dict(type='int', default=1),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
timeout=dict(type='int', default=60),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
params = module.params.copy()
|
||||||
|
|
||||||
|
state = module.params['state']
|
||||||
|
name = module.params['name']
|
||||||
|
cluster_template_id = module.params['cluster_template_id']
|
||||||
|
|
||||||
|
kwargs = dict(
|
||||||
|
discovery_url=module.params['discovery_url'],
|
||||||
|
docker_volume_size=module.params['docker_volume_size'],
|
||||||
|
flavor_id=module.params['flavor_id'],
|
||||||
|
keypair=module.params['keypair'],
|
||||||
|
labels=_parse_labels(params['labels']),
|
||||||
|
master_count=module.params['master_count'],
|
||||||
|
master_flavor_id=module.params['master_flavor_id'],
|
||||||
|
node_count=module.params['node_count'],
|
||||||
|
create_timeout=module.params['timeout'],
|
||||||
|
)
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
changed = False
|
||||||
|
cluster = cloud.get_coe_cluster(name_or_id=name, filters={'cluster_template_id': cluster_template_id})
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if not cluster:
|
||||||
|
cluster = cloud.create_coe_cluster(name, cluster_template_id=cluster_template_id, **kwargs)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
# NOTE (brtknr): At present, create_coe_cluster request returns
|
||||||
|
# cluster_id as `uuid` whereas get_coe_cluster request returns the
|
||||||
|
# same field as `id`. This behaviour may change in the future
|
||||||
|
# therefore try `id` first then `uuid`.
|
||||||
|
cluster_id = cluster.get('id', cluster.get('uuid'))
|
||||||
|
cluster['id'] = cluster['uuid'] = cluster_id
|
||||||
|
module.exit_json(changed=changed, cluster=cluster, id=cluster_id)
|
||||||
|
elif state == 'absent':
|
||||||
|
if not cluster:
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
else:
|
||||||
|
cloud.delete_coe_cluster(name)
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
394
plugins/modules/coe_cluster_template.py
Normal file
394
plugins/modules/coe_cluster_template.py
Normal file
@ -0,0 +1,394 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2018 Catalyst IT Ltd.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: coe_cluster_template
|
||||||
|
short_description: Add/Remove COE cluster template from OpenStack Cloud
|
||||||
|
author: "Feilong Wang (@flwang)"
|
||||||
|
description:
|
||||||
|
- Add or Remove COE cluster template from the OpenStack Container Infra
|
||||||
|
service.
|
||||||
|
options:
|
||||||
|
coe:
|
||||||
|
description:
|
||||||
|
- The Container Orchestration Engine for this clustertemplate
|
||||||
|
choices: [kubernetes, swarm, mesos]
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
dns_nameserver:
|
||||||
|
description:
|
||||||
|
- The DNS nameserver address
|
||||||
|
default: '8.8.8.8'
|
||||||
|
type: str
|
||||||
|
docker_storage_driver:
|
||||||
|
description:
|
||||||
|
- Docker storage driver
|
||||||
|
choices: [devicemapper, overlay, overlay2]
|
||||||
|
type: str
|
||||||
|
docker_volume_size:
|
||||||
|
description:
|
||||||
|
- The size in GB of the docker volume
|
||||||
|
type: int
|
||||||
|
external_network_id:
|
||||||
|
description:
|
||||||
|
- The external network to attach to the Cluster
|
||||||
|
type: str
|
||||||
|
fixed_network:
|
||||||
|
description:
|
||||||
|
- The fixed network name to attach to the Cluster
|
||||||
|
type: str
|
||||||
|
fixed_subnet:
|
||||||
|
description:
|
||||||
|
- The fixed subnet name to attach to the Cluster
|
||||||
|
type: str
|
||||||
|
flavor_id:
|
||||||
|
description:
|
||||||
|
- The flavor of the minion node for this ClusterTemplate
|
||||||
|
type: str
|
||||||
|
floating_ip_enabled:
|
||||||
|
description:
|
||||||
|
- Indicates whether created clusters should have a floating ip or not
|
||||||
|
type: bool
|
||||||
|
default: true
|
||||||
|
keypair_id:
|
||||||
|
description:
|
||||||
|
- Name or ID of the keypair to use.
|
||||||
|
type: str
|
||||||
|
image_id:
|
||||||
|
description:
|
||||||
|
- Image id the cluster will be based on
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
labels:
|
||||||
|
description:
|
||||||
|
- One or more key/value pairs
|
||||||
|
type: raw
|
||||||
|
http_proxy:
|
||||||
|
description:
|
||||||
|
- Address of a proxy that will receive all HTTP requests and relay them
|
||||||
|
The format is a URL including a port number
|
||||||
|
type: str
|
||||||
|
https_proxy:
|
||||||
|
description:
|
||||||
|
- Address of a proxy that will receive all HTTPS requests and relay
|
||||||
|
them. The format is a URL including a port number
|
||||||
|
type: str
|
||||||
|
master_flavor_id:
|
||||||
|
description:
|
||||||
|
- The flavor of the master node for this ClusterTemplate
|
||||||
|
type: str
|
||||||
|
master_lb_enabled:
|
||||||
|
description:
|
||||||
|
- Indicates whether created clusters should have a load balancer
|
||||||
|
for master nodes or not
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the cluster template
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
network_driver:
|
||||||
|
description:
|
||||||
|
- The name of the driver used for instantiating container networks
|
||||||
|
choices: [flannel, calico, docker]
|
||||||
|
type: str
|
||||||
|
no_proxy:
|
||||||
|
description:
|
||||||
|
- A comma separated list of IPs for which proxies should not be
|
||||||
|
used in the cluster
|
||||||
|
type: str
|
||||||
|
public:
|
||||||
|
description:
|
||||||
|
- Indicates whether the ClusterTemplate is public or not
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
registry_enabled:
|
||||||
|
description:
|
||||||
|
- Indicates whether the docker registry is enabled
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
server_type:
|
||||||
|
description:
|
||||||
|
- Server type for this ClusterTemplate
|
||||||
|
choices: [vm, bm]
|
||||||
|
default: vm
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Indicate desired state of the resource.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
tls_disabled:
|
||||||
|
description:
|
||||||
|
- Indicates whether the TLS should be disabled
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
volume_driver:
|
||||||
|
description:
|
||||||
|
- The name of the driver used for instantiating container volumes
|
||||||
|
choices: [cinder, rexray]
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
id:
|
||||||
|
description: The cluster UUID.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
cluster_template:
|
||||||
|
description: Dictionary describing the template.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
coe:
|
||||||
|
description: The Container Orchestration Engine for this clustertemplate
|
||||||
|
type: str
|
||||||
|
sample: kubernetes
|
||||||
|
dns_nameserver:
|
||||||
|
description: The DNS nameserver address
|
||||||
|
type: str
|
||||||
|
sample: '8.8.8.8'
|
||||||
|
docker_storage_driver:
|
||||||
|
description: Docker storage driver
|
||||||
|
type: str
|
||||||
|
sample: devicemapper
|
||||||
|
docker_volume_size:
|
||||||
|
description: The size in GB of the docker volume
|
||||||
|
type: int
|
||||||
|
sample: 5
|
||||||
|
external_network_id:
|
||||||
|
description: The external network to attach to the Cluster
|
||||||
|
type: str
|
||||||
|
sample: public
|
||||||
|
fixed_network:
|
||||||
|
description: The fixed network name to attach to the Cluster
|
||||||
|
type: str
|
||||||
|
sample: 07767ec6-85f5-44cb-bd63-242a8e7f0d9d
|
||||||
|
fixed_subnet:
|
||||||
|
description:
|
||||||
|
- The fixed subnet name to attach to the Cluster
|
||||||
|
type: str
|
||||||
|
sample: 05567ec6-85f5-44cb-bd63-242a8e7f0d9d
|
||||||
|
flavor_id:
|
||||||
|
description:
|
||||||
|
- The flavor of the minion node for this ClusterTemplate
|
||||||
|
type: str
|
||||||
|
sample: c1.c1r1
|
||||||
|
floating_ip_enabled:
|
||||||
|
description:
|
||||||
|
- Indicates whether created clusters should have a floating ip or not
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
keypair_id:
|
||||||
|
description:
|
||||||
|
- Name or ID of the keypair to use.
|
||||||
|
type: str
|
||||||
|
sample: mykey
|
||||||
|
image_id:
|
||||||
|
description:
|
||||||
|
- Image id the cluster will be based on
|
||||||
|
type: str
|
||||||
|
sample: 05567ec6-85f5-44cb-bd63-242a8e7f0e9d
|
||||||
|
labels:
|
||||||
|
description: One or more key/value pairs
|
||||||
|
type: dict
|
||||||
|
sample: {'key1': 'value1', 'key2': 'value2'}
|
||||||
|
http_proxy:
|
||||||
|
description:
|
||||||
|
- Address of a proxy that will receive all HTTP requests and relay them
|
||||||
|
The format is a URL including a port number
|
||||||
|
type: str
|
||||||
|
sample: http://10.0.0.11:9090
|
||||||
|
https_proxy:
|
||||||
|
description:
|
||||||
|
- Address of a proxy that will receive all HTTPS requests and relay
|
||||||
|
them. The format is a URL including a port number
|
||||||
|
type: str
|
||||||
|
sample: https://10.0.0.10:8443
|
||||||
|
master_flavor_id:
|
||||||
|
description:
|
||||||
|
- The flavor of the master node for this ClusterTemplate
|
||||||
|
type: str
|
||||||
|
sample: c1.c1r1
|
||||||
|
master_lb_enabled:
|
||||||
|
description:
|
||||||
|
- Indicates whether created clusters should have a load balancer
|
||||||
|
for master nodes or not
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the cluster template
|
||||||
|
type: str
|
||||||
|
sample: k8scluster
|
||||||
|
network_driver:
|
||||||
|
description:
|
||||||
|
- The name of the driver used for instantiating container networks
|
||||||
|
type: str
|
||||||
|
sample: calico
|
||||||
|
no_proxy:
|
||||||
|
description:
|
||||||
|
- A comma separated list of IPs for which proxies should not be
|
||||||
|
used in the cluster
|
||||||
|
type: str
|
||||||
|
sample: 10.0.0.4,10.0.0.5
|
||||||
|
public:
|
||||||
|
description:
|
||||||
|
- Indicates whether the ClusterTemplate is public or not
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
registry_enabled:
|
||||||
|
description:
|
||||||
|
- Indicates whether the docker registry is enabled
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
server_type:
|
||||||
|
description:
|
||||||
|
- Server type for this ClusterTemplate
|
||||||
|
type: str
|
||||||
|
sample: vm
|
||||||
|
tls_disabled:
|
||||||
|
description:
|
||||||
|
- Indicates whether the TLS should be disabled
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
volume_driver:
|
||||||
|
description:
|
||||||
|
- The name of the driver used for instantiating container volumes
|
||||||
|
type: str
|
||||||
|
sample: cinder
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a new Kubernetes cluster template
|
||||||
|
- openstack.cloud.coe_cluster_template:
|
||||||
|
name: k8s
|
||||||
|
coe: kubernetes
|
||||||
|
keypair_id: mykey
|
||||||
|
image_id: 2a8c9888-9054-4b06-a1ca-2bb61f9adb72
|
||||||
|
public: no
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_labels(labels):
|
||||||
|
if isinstance(labels, str):
|
||||||
|
labels_dict = {}
|
||||||
|
for kv_str in labels.split(","):
|
||||||
|
k, v = kv_str.split("=")
|
||||||
|
labels_dict[k] = v
|
||||||
|
return labels_dict
|
||||||
|
if not labels:
|
||||||
|
return {}
|
||||||
|
return labels
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
coe=dict(required=True, choices=['kubernetes', 'swarm', 'mesos']),
|
||||||
|
dns_nameserver=dict(default='8.8.8.8'),
|
||||||
|
docker_storage_driver=dict(choices=['devicemapper', 'overlay', 'overlay2']),
|
||||||
|
docker_volume_size=dict(type='int'),
|
||||||
|
external_network_id=dict(default=None),
|
||||||
|
fixed_network=dict(default=None),
|
||||||
|
fixed_subnet=dict(default=None),
|
||||||
|
flavor_id=dict(default=None),
|
||||||
|
floating_ip_enabled=dict(type='bool', default=True),
|
||||||
|
keypair_id=dict(default=None),
|
||||||
|
image_id=dict(required=True),
|
||||||
|
labels=dict(default=None, type='raw'),
|
||||||
|
http_proxy=dict(default=None),
|
||||||
|
https_proxy=dict(default=None),
|
||||||
|
master_lb_enabled=dict(type='bool', default=False),
|
||||||
|
master_flavor_id=dict(default=None),
|
||||||
|
name=dict(required=True),
|
||||||
|
network_driver=dict(choices=['flannel', 'calico', 'docker']),
|
||||||
|
no_proxy=dict(default=None),
|
||||||
|
public=dict(type='bool', default=False),
|
||||||
|
registry_enabled=dict(type='bool', default=False),
|
||||||
|
server_type=dict(default="vm", choices=['vm', 'bm']),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
tls_disabled=dict(type='bool', default=False),
|
||||||
|
volume_driver=dict(choices=['cinder', 'rexray']),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
params = module.params.copy()
|
||||||
|
|
||||||
|
state = module.params['state']
|
||||||
|
name = module.params['name']
|
||||||
|
coe = module.params['coe']
|
||||||
|
image_id = module.params['image_id']
|
||||||
|
|
||||||
|
kwargs = dict(
|
||||||
|
dns_nameserver=module.params['dns_nameserver'],
|
||||||
|
docker_storage_driver=module.params['docker_storage_driver'],
|
||||||
|
docker_volume_size=module.params['docker_volume_size'],
|
||||||
|
external_network_id=module.params['external_network_id'],
|
||||||
|
fixed_network=module.params['fixed_network'],
|
||||||
|
fixed_subnet=module.params['fixed_subnet'],
|
||||||
|
flavor_id=module.params['flavor_id'],
|
||||||
|
floating_ip_enabled=module.params['floating_ip_enabled'],
|
||||||
|
keypair_id=module.params['keypair_id'],
|
||||||
|
labels=_parse_labels(params['labels']),
|
||||||
|
http_proxy=module.params['http_proxy'],
|
||||||
|
https_proxy=module.params['https_proxy'],
|
||||||
|
master_lb_enabled=module.params['master_lb_enabled'],
|
||||||
|
master_flavor_id=module.params['master_flavor_id'],
|
||||||
|
network_driver=module.params['network_driver'],
|
||||||
|
no_proxy=module.params['no_proxy'],
|
||||||
|
public=module.params['public'],
|
||||||
|
registry_enabled=module.params['registry_enabled'],
|
||||||
|
server_type=module.params['server_type'],
|
||||||
|
tls_disabled=module.params['tls_disabled'],
|
||||||
|
volume_driver=module.params['volume_driver'],
|
||||||
|
)
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
changed = False
|
||||||
|
template = cloud.get_coe_cluster_template(name_or_id=name, filters={'coe': coe, 'image_id': image_id})
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if not template:
|
||||||
|
template = cloud.create_coe_cluster_template(name, coe=coe, image_id=image_id, **kwargs)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
module.exit_json(changed=changed, cluster_template=template, id=template['uuid'])
|
||||||
|
elif state == 'absent':
|
||||||
|
if not template:
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
else:
|
||||||
|
cloud.delete_coe_cluster_template(name)
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
280
plugins/modules/compute_flavor.py
Normal file
280
plugins/modules/compute_flavor.py
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: compute_flavor
|
||||||
|
short_description: Manage OpenStack compute flavors
|
||||||
|
author: "David Shrewsbury (@Shrews)"
|
||||||
|
description:
|
||||||
|
- Add or remove flavors from OpenStack.
|
||||||
|
options:
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Indicate desired state of the resource. When I(state) is 'present',
|
||||||
|
then I(ram), I(vcpus), and I(disk) are all required. There are no
|
||||||
|
default values for those parameters.
|
||||||
|
choices: ['present', 'absent']
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Flavor name.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
ram:
|
||||||
|
description:
|
||||||
|
- Amount of memory, in MB.
|
||||||
|
type: int
|
||||||
|
vcpus:
|
||||||
|
description:
|
||||||
|
- Number of virtual CPUs.
|
||||||
|
type: int
|
||||||
|
disk:
|
||||||
|
description:
|
||||||
|
- Size of local disk, in GB.
|
||||||
|
default: 0
|
||||||
|
type: int
|
||||||
|
ephemeral:
|
||||||
|
description:
|
||||||
|
- Ephemeral space size, in GB.
|
||||||
|
default: 0
|
||||||
|
type: int
|
||||||
|
swap:
|
||||||
|
description:
|
||||||
|
- Swap space size, in MB.
|
||||||
|
default: 0
|
||||||
|
type: int
|
||||||
|
rxtx_factor:
|
||||||
|
description:
|
||||||
|
- RX/TX factor.
|
||||||
|
default: 1.0
|
||||||
|
type: float
|
||||||
|
is_public:
|
||||||
|
description:
|
||||||
|
- Make flavor accessible to the public.
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
flavorid:
|
||||||
|
description:
|
||||||
|
- ID for the flavor. This is optional as a unique UUID will be
|
||||||
|
assigned if a value is not specified.
|
||||||
|
default: "auto"
|
||||||
|
type: str
|
||||||
|
extra_specs:
|
||||||
|
description:
|
||||||
|
- Metadata dictionary
|
||||||
|
type: dict
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: "Create 'tiny' flavor with 1024MB of RAM, 1 virtual CPU, and 10GB of local disk, and 10GB of ephemeral."
|
||||||
|
openstack.cloud.compute_flavor:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: tiny
|
||||||
|
ram: 1024
|
||||||
|
vcpus: 1
|
||||||
|
disk: 10
|
||||||
|
ephemeral: 10
|
||||||
|
|
||||||
|
- name: "Delete 'tiny' flavor"
|
||||||
|
openstack.cloud.compute_flavor:
|
||||||
|
cloud: mycloud
|
||||||
|
state: absent
|
||||||
|
name: tiny
|
||||||
|
|
||||||
|
- name: Create flavor with metadata
|
||||||
|
openstack.cloud.compute_flavor:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: tiny
|
||||||
|
ram: 1024
|
||||||
|
vcpus: 1
|
||||||
|
disk: 10
|
||||||
|
extra_specs:
|
||||||
|
"quota:disk_read_iops_sec": 5000
|
||||||
|
"aggregate_instance_extra_specs:pinned": false
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
flavor:
|
||||||
|
description: Dictionary describing the flavor.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Flavor ID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: "515256b8-7027-4d73-aa54-4e30a4a4a339"
|
||||||
|
name:
|
||||||
|
description: Flavor name.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: "tiny"
|
||||||
|
disk:
|
||||||
|
description: Size of local disk, in GB.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 10
|
||||||
|
ephemeral:
|
||||||
|
description: Ephemeral space size, in GB.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 10
|
||||||
|
ram:
|
||||||
|
description: Amount of memory, in MB.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 1024
|
||||||
|
swap:
|
||||||
|
description: Swap space size, in MB.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 100
|
||||||
|
vcpus:
|
||||||
|
description: Number of virtual CPUs.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 2
|
||||||
|
is_public:
|
||||||
|
description: Make flavor accessible to the public.
|
||||||
|
returned: success
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
extra_specs:
|
||||||
|
description: Flavor metadata
|
||||||
|
returned: success
|
||||||
|
type: dict
|
||||||
|
sample:
|
||||||
|
"quota:disk_read_iops_sec": 5000
|
||||||
|
"aggregate_instance_extra_specs:pinned": false
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(module, flavor):
|
||||||
|
state = module.params['state']
|
||||||
|
if state == 'present' and not flavor:
|
||||||
|
return True
|
||||||
|
if state == 'absent' and flavor:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
state=dict(required=False, default='present',
|
||||||
|
choices=['absent', 'present']),
|
||||||
|
name=dict(required=True),
|
||||||
|
|
||||||
|
# required when state is 'present'
|
||||||
|
ram=dict(required=False, type='int'),
|
||||||
|
vcpus=dict(required=False, type='int'),
|
||||||
|
|
||||||
|
disk=dict(required=False, default=0, type='int'),
|
||||||
|
ephemeral=dict(required=False, default=0, type='int'),
|
||||||
|
swap=dict(required=False, default=0, type='int'),
|
||||||
|
rxtx_factor=dict(required=False, default=1.0, type='float'),
|
||||||
|
is_public=dict(required=False, default=True, type='bool'),
|
||||||
|
flavorid=dict(required=False, default="auto"),
|
||||||
|
extra_specs=dict(required=False, default=None, type='dict'),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
required_if=[
|
||||||
|
('state', 'present', ['ram', 'vcpus', 'disk'])
|
||||||
|
],
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
state = module.params['state']
|
||||||
|
name = module.params['name']
|
||||||
|
extra_specs = module.params['extra_specs'] or {}
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
flavor = cloud.get_flavor(name)
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(module, flavor))
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
old_extra_specs = {}
|
||||||
|
require_update = False
|
||||||
|
|
||||||
|
if flavor:
|
||||||
|
old_extra_specs = flavor['extra_specs']
|
||||||
|
for param_key in ['ram', 'vcpus', 'disk', 'ephemeral', 'swap', 'rxtx_factor', 'is_public']:
|
||||||
|
if module.params[param_key] != flavor[param_key]:
|
||||||
|
require_update = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if flavor and require_update:
|
||||||
|
cloud.delete_flavor(name)
|
||||||
|
flavor = None
|
||||||
|
|
||||||
|
if not flavor:
|
||||||
|
flavor = cloud.create_flavor(
|
||||||
|
name=name,
|
||||||
|
ram=module.params['ram'],
|
||||||
|
vcpus=module.params['vcpus'],
|
||||||
|
disk=module.params['disk'],
|
||||||
|
flavorid=module.params['flavorid'],
|
||||||
|
ephemeral=module.params['ephemeral'],
|
||||||
|
swap=module.params['swap'],
|
||||||
|
rxtx_factor=module.params['rxtx_factor'],
|
||||||
|
is_public=module.params['is_public']
|
||||||
|
)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
new_extra_specs = dict([(k, str(v)) for k, v in extra_specs.items()])
|
||||||
|
unset_keys = set(old_extra_specs.keys()) - set(extra_specs.keys())
|
||||||
|
|
||||||
|
if unset_keys and not require_update:
|
||||||
|
cloud.unset_flavor_specs(flavor['id'], unset_keys)
|
||||||
|
|
||||||
|
if old_extra_specs != new_extra_specs:
|
||||||
|
cloud.set_flavor_specs(flavor['id'], extra_specs)
|
||||||
|
|
||||||
|
changed = (changed or old_extra_specs != new_extra_specs)
|
||||||
|
|
||||||
|
module.exit_json(changed=changed,
|
||||||
|
flavor=flavor,
|
||||||
|
id=flavor['id'])
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if flavor:
|
||||||
|
cloud.delete_flavor(name)
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
233
plugins/modules/compute_flavor_info.py
Normal file
233
plugins/modules/compute_flavor_info.py
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2015 IBM
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: compute_flavor_info
|
||||||
|
short_description: Retrieve information about one or more flavors
|
||||||
|
author: "David Shrewsbury (@Shrews)"
|
||||||
|
description:
|
||||||
|
- Retrieve information about available OpenStack instance flavors. By default,
|
||||||
|
information about ALL flavors are retrieved. Filters can be applied to get
|
||||||
|
information for only matching flavors. For example, you can filter on the
|
||||||
|
amount of RAM available to the flavor, or the number of virtual CPUs
|
||||||
|
available to the flavor, or both. When specifying multiple filters,
|
||||||
|
*ALL* filters must match on a flavor before that flavor is returned as
|
||||||
|
a fact.
|
||||||
|
- This module was called C(openstack.cloud.compute_flavor_facts) before Ansible 2.9, returning C(ansible_facts).
|
||||||
|
Note that the M(openstack.cloud.compute_flavor_info) module no longer returns C(ansible_facts)!
|
||||||
|
notes:
|
||||||
|
- The result contains a list of unsorted flavors.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- A flavor name. Cannot be used with I(ram) or I(vcpus) or I(ephemeral).
|
||||||
|
type: str
|
||||||
|
ram:
|
||||||
|
description:
|
||||||
|
- "A string used for filtering flavors based on the amount of RAM
|
||||||
|
(in MB) desired. This string accepts the following special values:
|
||||||
|
'MIN' (return flavors with the minimum amount of RAM), and 'MAX'
|
||||||
|
(return flavors with the maximum amount of RAM)."
|
||||||
|
|
||||||
|
- "A specific amount of RAM may also be specified. Any flavors with this
|
||||||
|
exact amount of RAM will be returned."
|
||||||
|
|
||||||
|
- "A range of acceptable RAM may be given using a special syntax. Simply
|
||||||
|
prefix the amount of RAM with one of these acceptable range values:
|
||||||
|
'<', '>', '<=', '>='. These values represent less than, greater than,
|
||||||
|
less than or equal to, and greater than or equal to, respectively."
|
||||||
|
type: str
|
||||||
|
vcpus:
|
||||||
|
description:
|
||||||
|
- A string used for filtering flavors based on the number of virtual
|
||||||
|
CPUs desired. Format is the same as the I(ram) parameter.
|
||||||
|
type: str
|
||||||
|
limit:
|
||||||
|
description:
|
||||||
|
- Limits the number of flavors returned. All matching flavors are
|
||||||
|
returned by default.
|
||||||
|
type: int
|
||||||
|
ephemeral:
|
||||||
|
description:
|
||||||
|
- A string used for filtering flavors based on the amount of ephemeral
|
||||||
|
storage. Format is the same as the I(ram) parameter
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Gather information about all available flavors
|
||||||
|
- openstack.cloud.compute_flavor_info:
|
||||||
|
cloud: mycloud
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- debug:
|
||||||
|
msg: "{{ result.openstack_flavors }}"
|
||||||
|
|
||||||
|
# Gather information for the flavor named "xlarge-flavor"
|
||||||
|
- openstack.cloud.compute_flavor_info:
|
||||||
|
cloud: mycloud
|
||||||
|
name: "xlarge-flavor"
|
||||||
|
|
||||||
|
# Get all flavors that have exactly 512 MB of RAM.
|
||||||
|
- openstack.cloud.compute_flavor_info:
|
||||||
|
cloud: mycloud
|
||||||
|
ram: "512"
|
||||||
|
|
||||||
|
# Get all flavors that have 1024 MB or more of RAM.
|
||||||
|
- openstack.cloud.compute_flavor_info:
|
||||||
|
cloud: mycloud
|
||||||
|
ram: ">=1024"
|
||||||
|
|
||||||
|
# Get a single flavor that has the minimum amount of RAM. Using the 'limit'
|
||||||
|
# option will guarantee only a single flavor is returned.
|
||||||
|
- openstack.cloud.compute_flavor_info:
|
||||||
|
cloud: mycloud
|
||||||
|
ram: "MIN"
|
||||||
|
limit: 1
|
||||||
|
|
||||||
|
# Get all flavors with 1024 MB of RAM or more, AND exactly 2 virtual CPUs.
|
||||||
|
- openstack.cloud.compute_flavor_info:
|
||||||
|
cloud: mycloud
|
||||||
|
ram: ">=1024"
|
||||||
|
vcpus: "2"
|
||||||
|
|
||||||
|
# Get all flavors with 1024 MB of RAM or more, exactly 2 virtual CPUs, and
|
||||||
|
# less than 30gb of ephemeral storage.
|
||||||
|
- openstack.cloud.compute_flavor_info:
|
||||||
|
cloud: mycloud
|
||||||
|
ram: ">=1024"
|
||||||
|
vcpus: "2"
|
||||||
|
ephemeral: "<30"
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
openstack_flavors:
|
||||||
|
description: Dictionary describing the flavors.
|
||||||
|
returned: On success.
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Flavor ID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: "515256b8-7027-4d73-aa54-4e30a4a4a339"
|
||||||
|
name:
|
||||||
|
description: Flavor name.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
sample: "tiny"
|
||||||
|
disk:
|
||||||
|
description: Size of local disk, in GB.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 10
|
||||||
|
ephemeral:
|
||||||
|
description: Ephemeral space size, in GB.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 10
|
||||||
|
ram:
|
||||||
|
description: Amount of memory, in MB.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 1024
|
||||||
|
swap:
|
||||||
|
description: Swap space size, in MB.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 100
|
||||||
|
vcpus:
|
||||||
|
description: Number of virtual CPUs.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
sample: 2
|
||||||
|
is_public:
|
||||||
|
description: Make flavor accessible to the public.
|
||||||
|
returned: success
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=False, default=None),
|
||||||
|
ram=dict(required=False, default=None),
|
||||||
|
vcpus=dict(required=False, default=None),
|
||||||
|
limit=dict(required=False, default=None, type='int'),
|
||||||
|
ephemeral=dict(required=False, default=None),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
mutually_exclusive=[
|
||||||
|
['name', 'ram'],
|
||||||
|
['name', 'vcpus'],
|
||||||
|
['name', 'ephemeral']
|
||||||
|
]
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
is_old_facts = module._name == 'openstack.cloud.compute_flavor_facts'
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'openstack.cloud.compute_flavor_facts' module has been renamed to 'openstack.cloud.compute_flavor_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts", version='2.13')
|
||||||
|
|
||||||
|
name = module.params['name']
|
||||||
|
vcpus = module.params['vcpus']
|
||||||
|
ram = module.params['ram']
|
||||||
|
ephemeral = module.params['ephemeral']
|
||||||
|
limit = module.params['limit']
|
||||||
|
|
||||||
|
filters = {}
|
||||||
|
if vcpus:
|
||||||
|
filters['vcpus'] = vcpus
|
||||||
|
if ram:
|
||||||
|
filters['ram'] = ram
|
||||||
|
if ephemeral:
|
||||||
|
filters['ephemeral'] = ephemeral
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
if name:
|
||||||
|
flavors = cloud.search_flavors(filters={'name': name})
|
||||||
|
|
||||||
|
else:
|
||||||
|
flavors = cloud.list_flavors()
|
||||||
|
if filters:
|
||||||
|
flavors = cloud.range_search(flavors, filters)
|
||||||
|
|
||||||
|
if limit is not None:
|
||||||
|
flavors = flavors[:limit]
|
||||||
|
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False,
|
||||||
|
ansible_facts=dict(openstack_flavors=flavors))
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False,
|
||||||
|
openstack_flavors=flavors)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
82
plugins/modules/config.py
Normal file
82
plugins/modules/config.py
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: config
|
||||||
|
short_description: Get OpenStack Client config
|
||||||
|
description:
|
||||||
|
- Get I(openstack) client config data from clouds.yaml or environment
|
||||||
|
notes:
|
||||||
|
- Facts are placed in the C(openstack.clouds) variable.
|
||||||
|
options:
|
||||||
|
clouds:
|
||||||
|
description:
|
||||||
|
- List of clouds to limit the return list to. No value means return
|
||||||
|
information on all configured clouds
|
||||||
|
required: false
|
||||||
|
default: []
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
author: "Monty Taylor (@emonty)"
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Get list of clouds that do not support security groups
|
||||||
|
openstack.cloud.config:
|
||||||
|
|
||||||
|
- debug:
|
||||||
|
var: "{{ item }}"
|
||||||
|
with_items: "{{ openstack.clouds | rejectattr('secgroup_source', 'none') | list }}"
|
||||||
|
|
||||||
|
- name: Get the information back just about the mordred cloud
|
||||||
|
openstack.cloud.config:
|
||||||
|
clouds:
|
||||||
|
- mordred
|
||||||
|
'''
|
||||||
|
|
||||||
|
try:
|
||||||
|
import openstack.config
|
||||||
|
from openstack import exceptions
|
||||||
|
HAS_OPENSTACKSDK = True
|
||||||
|
except ImportError:
|
||||||
|
HAS_OPENSTACKSDK = False
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(argument_spec=dict(
|
||||||
|
clouds=dict(required=False, type='list', default=[], elements='str'),
|
||||||
|
))
|
||||||
|
|
||||||
|
if not HAS_OPENSTACKSDK:
|
||||||
|
module.fail_json(msg='openstacksdk is required for this module')
|
||||||
|
|
||||||
|
p = module.params
|
||||||
|
|
||||||
|
try:
|
||||||
|
config = openstack.config.OpenStackConfig()
|
||||||
|
clouds = []
|
||||||
|
for cloud in config.get_all_clouds():
|
||||||
|
if not p['clouds'] or cloud.name in p['clouds']:
|
||||||
|
cloud.config['name'] = cloud.name
|
||||||
|
clouds.append(cloud.config)
|
||||||
|
module.exit_json(ansible_facts=dict(openstack=dict(clouds=clouds)))
|
||||||
|
except exceptions.ConfigException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
248
plugins/modules/dns_zone.py
Normal file
248
plugins/modules/dns_zone.py
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2016 Hewlett-Packard Enterprise
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: dns_zone
|
||||||
|
short_description: Manage OpenStack DNS zones
|
||||||
|
author: "Ricardo Carrillo Cruz (@rcarrillocruz)"
|
||||||
|
description:
|
||||||
|
- Manage OpenStack DNS zones. Zones can be created, deleted or
|
||||||
|
updated. Only the I(email), I(description), I(ttl) and I(masters) values
|
||||||
|
can be updated.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Zone name
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
zone_type:
|
||||||
|
description:
|
||||||
|
- Zone type
|
||||||
|
choices: [primary, secondary]
|
||||||
|
type: str
|
||||||
|
email:
|
||||||
|
description:
|
||||||
|
- Email of the zone owner (only applies if zone_type is primary)
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
description:
|
||||||
|
- Zone description
|
||||||
|
type: str
|
||||||
|
ttl:
|
||||||
|
description:
|
||||||
|
- TTL (Time To Live) value in seconds
|
||||||
|
type: int
|
||||||
|
masters:
|
||||||
|
description:
|
||||||
|
- Master nameservers (only applies if zone_type is secondary)
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a zone named "example.net"
|
||||||
|
- openstack.cloud.dns_zone:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: example.net.
|
||||||
|
zone_type: primary
|
||||||
|
email: test@example.net
|
||||||
|
description: Test zone
|
||||||
|
ttl: 3600
|
||||||
|
|
||||||
|
# Update the TTL on existing "example.net." zone
|
||||||
|
- openstack.cloud.dns_zone:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: example.net.
|
||||||
|
ttl: 7200
|
||||||
|
|
||||||
|
# Delete zone named "example.net."
|
||||||
|
- openstack.cloud.dns_zone:
|
||||||
|
cloud: mycloud
|
||||||
|
state: absent
|
||||||
|
name: example.net.
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
zone:
|
||||||
|
description: Dictionary describing the zone.
|
||||||
|
returned: On success when I(state) is 'present'.
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique zone ID
|
||||||
|
type: str
|
||||||
|
sample: "c1c530a3-3619-46f3-b0f6-236927b2618c"
|
||||||
|
name:
|
||||||
|
description: Zone name
|
||||||
|
type: str
|
||||||
|
sample: "example.net."
|
||||||
|
type:
|
||||||
|
description: Zone type
|
||||||
|
type: str
|
||||||
|
sample: "PRIMARY"
|
||||||
|
email:
|
||||||
|
description: Zone owner email
|
||||||
|
type: str
|
||||||
|
sample: "test@example.net"
|
||||||
|
description:
|
||||||
|
description: Zone description
|
||||||
|
type: str
|
||||||
|
sample: "Test description"
|
||||||
|
ttl:
|
||||||
|
description: Zone TTL value
|
||||||
|
type: int
|
||||||
|
sample: 3600
|
||||||
|
masters:
|
||||||
|
description: Zone master nameservers
|
||||||
|
type: list
|
||||||
|
sample: []
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(state, email, description, ttl, masters, zone):
|
||||||
|
if state == 'present':
|
||||||
|
if not zone:
|
||||||
|
return True
|
||||||
|
if email is not None and zone.email != email:
|
||||||
|
return True
|
||||||
|
if description is not None and zone.description != description:
|
||||||
|
return True
|
||||||
|
if ttl is not None and zone.ttl != ttl:
|
||||||
|
return True
|
||||||
|
if masters is not None and zone.masters != masters:
|
||||||
|
return True
|
||||||
|
if state == 'absent' and zone:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _wait(timeout, cloud, zone, state, module, sdk):
|
||||||
|
"""Wait for a zone to reach the desired state for the given state."""
|
||||||
|
|
||||||
|
for count in sdk.utils.iterate_timeout(
|
||||||
|
timeout,
|
||||||
|
"Timeout waiting for zone to be %s" % state):
|
||||||
|
|
||||||
|
if (state == 'absent' and zone is None) or (state == 'present' and zone and zone.status == 'ACTIVE'):
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
zone = cloud.get_zone(zone.id)
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if zone and zone.status == 'ERROR':
|
||||||
|
module.fail_json(msg="Zone reached ERROR state while waiting for it to be %s" % state)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
zone_type=dict(required=False, choices=['primary', 'secondary']),
|
||||||
|
email=dict(required=False, default=None),
|
||||||
|
description=dict(required=False, default=None),
|
||||||
|
ttl=dict(required=False, default=None, type='int'),
|
||||||
|
masters=dict(required=False, default=None, type='list', elements='str'),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
name = module.params.get('name')
|
||||||
|
state = module.params.get('state')
|
||||||
|
wait = module.params.get('wait')
|
||||||
|
timeout = module.params.get('timeout')
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
zone = cloud.get_zone(name)
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
zone_type = module.params.get('zone_type')
|
||||||
|
email = module.params.get('email')
|
||||||
|
description = module.params.get('description')
|
||||||
|
ttl = module.params.get('ttl')
|
||||||
|
masters = module.params.get('masters')
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(state, email,
|
||||||
|
description, ttl,
|
||||||
|
masters, zone))
|
||||||
|
|
||||||
|
if zone is None:
|
||||||
|
zone = cloud.create_zone(
|
||||||
|
name=name, zone_type=zone_type, email=email,
|
||||||
|
description=description, ttl=ttl, masters=masters)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
if masters is None:
|
||||||
|
masters = []
|
||||||
|
|
||||||
|
pre_update_zone = zone
|
||||||
|
changed = _system_state_change(state, email,
|
||||||
|
description, ttl,
|
||||||
|
masters, pre_update_zone)
|
||||||
|
if changed:
|
||||||
|
zone = cloud.update_zone(
|
||||||
|
name, email=email,
|
||||||
|
description=description,
|
||||||
|
ttl=ttl, masters=masters)
|
||||||
|
|
||||||
|
if wait:
|
||||||
|
_wait(timeout, cloud, zone, state, module, sdk)
|
||||||
|
|
||||||
|
module.exit_json(changed=changed, zone=zone)
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(state, None,
|
||||||
|
None, None,
|
||||||
|
None, zone))
|
||||||
|
|
||||||
|
if zone is None:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
cloud.delete_zone(name)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if wait:
|
||||||
|
_wait(timeout, cloud, zone, state, module, sdk)
|
||||||
|
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
215
plugins/modules/endpoint.py
Normal file
215
plugins/modules/endpoint.py
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2017, VEXXHOST, Inc.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: endpoint
|
||||||
|
short_description: Manage OpenStack Identity service endpoints
|
||||||
|
author:
|
||||||
|
- Mohammed Naser (@mnaser)
|
||||||
|
- Alberto Murillo (@albertomurillo)
|
||||||
|
description:
|
||||||
|
- Create, update, or delete OpenStack Identity service endpoints. If a
|
||||||
|
service with the same combination of I(service), I(interface) and I(region)
|
||||||
|
exist, the I(url) and I(state) (C(present) or C(absent)) will be updated.
|
||||||
|
options:
|
||||||
|
service:
|
||||||
|
description:
|
||||||
|
- Name or id of the service.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
endpoint_interface:
|
||||||
|
description:
|
||||||
|
- Interface of the service.
|
||||||
|
choices: [admin, public, internal]
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
url:
|
||||||
|
description:
|
||||||
|
- URL of the service.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
region:
|
||||||
|
description:
|
||||||
|
- Region that the service belongs to. Note that I(region_name) is used for authentication.
|
||||||
|
type: str
|
||||||
|
enabled:
|
||||||
|
description:
|
||||||
|
- Is the service enabled.
|
||||||
|
default: True
|
||||||
|
type: bool
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be C(present) or C(absent).
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk >= 0.13.0"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Create a service for glance
|
||||||
|
openstack.cloud.endpoint:
|
||||||
|
cloud: mycloud
|
||||||
|
service: glance
|
||||||
|
endpoint_interface: public
|
||||||
|
url: http://controller:9292
|
||||||
|
region: RegionOne
|
||||||
|
state: present
|
||||||
|
|
||||||
|
- name: Delete a service for nova
|
||||||
|
openstack.cloud.endpoint:
|
||||||
|
cloud: mycloud
|
||||||
|
service: nova
|
||||||
|
endpoint_interface: public
|
||||||
|
region: RegionOne
|
||||||
|
state: absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
endpoint:
|
||||||
|
description: Dictionary describing the endpoint.
|
||||||
|
returned: On success when I(state) is C(present)
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Endpoint ID.
|
||||||
|
type: str
|
||||||
|
sample: 3292f020780b4d5baf27ff7e1d224c44
|
||||||
|
region:
|
||||||
|
description: Region Name.
|
||||||
|
type: str
|
||||||
|
sample: RegionOne
|
||||||
|
service_id:
|
||||||
|
description: Service ID.
|
||||||
|
type: str
|
||||||
|
sample: b91f1318f735494a825a55388ee118f3
|
||||||
|
interface:
|
||||||
|
description: Endpoint Interface.
|
||||||
|
type: str
|
||||||
|
sample: public
|
||||||
|
url:
|
||||||
|
description: Service URL.
|
||||||
|
type: str
|
||||||
|
sample: http://controller:9292
|
||||||
|
enabled:
|
||||||
|
description: Service status.
|
||||||
|
type: bool
|
||||||
|
sample: True
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _needs_update(module, endpoint):
|
||||||
|
if endpoint.enabled != module.params['enabled']:
|
||||||
|
return True
|
||||||
|
if endpoint.url != module.params['url']:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(module, endpoint):
|
||||||
|
state = module.params['state']
|
||||||
|
if state == 'absent' and endpoint:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if endpoint is None:
|
||||||
|
return True
|
||||||
|
return _needs_update(module, endpoint)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
service=dict(type='str', required=True),
|
||||||
|
endpoint_interface=dict(type='str', required=True, choices=['admin', 'public', 'internal']),
|
||||||
|
url=dict(type='str', required=True),
|
||||||
|
region=dict(type='str'),
|
||||||
|
enabled=dict(type='bool', default=True),
|
||||||
|
state=dict(type='str', default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
service_name_or_id = module.params['service']
|
||||||
|
interface = module.params['endpoint_interface']
|
||||||
|
url = module.params['url']
|
||||||
|
region = module.params['region']
|
||||||
|
enabled = module.params['enabled']
|
||||||
|
state = module.params['state']
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
|
||||||
|
service = cloud.get_service(service_name_or_id)
|
||||||
|
if service is None:
|
||||||
|
module.fail_json(msg='Service %s does not exist' % service_name_or_id)
|
||||||
|
|
||||||
|
filters = dict(service_id=service.id, interface=interface)
|
||||||
|
if region is not None:
|
||||||
|
filters['region'] = region
|
||||||
|
endpoints = cloud.search_endpoints(filters=filters)
|
||||||
|
|
||||||
|
if len(endpoints) > 1:
|
||||||
|
module.fail_json(msg='Service %s, interface %s and region %s are '
|
||||||
|
'not unique' %
|
||||||
|
(service_name_or_id, interface, region))
|
||||||
|
elif len(endpoints) == 1:
|
||||||
|
endpoint = endpoints[0]
|
||||||
|
else:
|
||||||
|
endpoint = None
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(module, endpoint))
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if endpoint is None:
|
||||||
|
result = cloud.create_endpoint(service_name_or_id=service,
|
||||||
|
url=url, interface=interface,
|
||||||
|
region=region, enabled=enabled)
|
||||||
|
endpoint = result[0]
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
if _needs_update(module, endpoint):
|
||||||
|
endpoint = cloud.update_endpoint(
|
||||||
|
endpoint.id, url=url, enabled=enabled)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
module.exit_json(changed=changed, endpoint=endpoint)
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if endpoint is None:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
cloud.delete_endpoint(endpoint.id)
|
||||||
|
changed = True
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
248
plugins/modules/federation_idp.py
Normal file
248
plugins/modules/federation_idp.py
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: federation_idp
|
||||||
|
short_description: manage a federation Identity Provider
|
||||||
|
author:
|
||||||
|
- "Mark Chappell (@tremble) <mchappel@redhat.com>"
|
||||||
|
description:
|
||||||
|
- Manage a federation Identity Provider.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the Identity Provider.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
aliases: ['id']
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Whether the Identity Provider should be C(present) or C(absent).
|
||||||
|
choices: ['present', 'absent']
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
description:
|
||||||
|
- The description of the Identity Provider.
|
||||||
|
type: str
|
||||||
|
domain_id:
|
||||||
|
description:
|
||||||
|
- The ID of a domain that is associated with the Identity Provider.
|
||||||
|
Federated users that authenticate with the Identity Provider will be
|
||||||
|
created under the domain specified.
|
||||||
|
- Required when creating a new Identity Provider.
|
||||||
|
type: str
|
||||||
|
enabled:
|
||||||
|
description:
|
||||||
|
- Whether the Identity Provider is enabled or not.
|
||||||
|
- Will default to C(true) when creating a new Identity Provider.
|
||||||
|
type: bool
|
||||||
|
aliases: ['is_enabled']
|
||||||
|
remote_ids:
|
||||||
|
description:
|
||||||
|
- "List of the unique Identity Provider's remote IDs."
|
||||||
|
- Will default to an empty list when creating a new Identity Provider.
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk >= 0.44"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Create an identity provider
|
||||||
|
openstack.cloud.federation_idp:
|
||||||
|
cloud: example_cloud
|
||||||
|
name: example_provider
|
||||||
|
domain_id: 0123456789abcdef0123456789abcdef
|
||||||
|
description: 'My example IDP'
|
||||||
|
remote_ids:
|
||||||
|
- 'https://auth.example.com/auth/realms/ExampleRealm'
|
||||||
|
|
||||||
|
- name: Delete an identity provider
|
||||||
|
openstack.cloud.federation_idp:
|
||||||
|
cloud: example_cloud
|
||||||
|
name: example_provider
|
||||||
|
state: absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_module_kwargs
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_cloud_from_module
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_idp(idp):
|
||||||
|
"""
|
||||||
|
Normalizes the IDP definitions so that the outputs are consistent with the
|
||||||
|
parameters
|
||||||
|
|
||||||
|
- "enabled" (parameter) == "is_enabled" (SDK)
|
||||||
|
- "name" (parameter) == "id" (SDK)
|
||||||
|
"""
|
||||||
|
if idp is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
_idp = idp.to_dict()
|
||||||
|
_idp['enabled'] = idp['is_enabled']
|
||||||
|
_idp['name'] = idp['id']
|
||||||
|
return _idp
|
||||||
|
|
||||||
|
|
||||||
|
def delete_identity_provider(module, sdk, cloud, idp):
|
||||||
|
"""
|
||||||
|
Delete an existing Identity Provider
|
||||||
|
|
||||||
|
returns: the "Changed" state
|
||||||
|
"""
|
||||||
|
|
||||||
|
if idp is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
cloud.identity.delete_identity_provider(idp)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to delete identity provider: {0}'.format(str(ex)))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def create_identity_provider(module, sdk, cloud, name):
|
||||||
|
"""
|
||||||
|
Create a new Identity Provider
|
||||||
|
|
||||||
|
returns: the "Changed" state and the new identity provider
|
||||||
|
"""
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return True, None
|
||||||
|
|
||||||
|
description = module.params.get('description')
|
||||||
|
enabled = module.params.get('enabled')
|
||||||
|
domain_id = module.params.get('domain_id')
|
||||||
|
remote_ids = module.params.get('remote_ids')
|
||||||
|
|
||||||
|
if enabled is None:
|
||||||
|
enabled = True
|
||||||
|
if remote_ids is None:
|
||||||
|
remote_ids = []
|
||||||
|
|
||||||
|
attributes = {
|
||||||
|
'domain_id': domain_id,
|
||||||
|
'enabled': enabled,
|
||||||
|
'remote_ids': remote_ids,
|
||||||
|
}
|
||||||
|
if description is not None:
|
||||||
|
attributes['description'] = description
|
||||||
|
|
||||||
|
try:
|
||||||
|
idp = cloud.identity.create_identity_provider(id=name, **attributes)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to create identity provider: {0}'.format(str(ex)))
|
||||||
|
return (True, idp)
|
||||||
|
|
||||||
|
|
||||||
|
def update_identity_provider(module, sdk, cloud, idp):
|
||||||
|
"""
|
||||||
|
Update an existing Identity Provider
|
||||||
|
|
||||||
|
returns: the "Changed" state and the new identity provider
|
||||||
|
"""
|
||||||
|
|
||||||
|
description = module.params.get('description')
|
||||||
|
enabled = module.params.get('enabled')
|
||||||
|
domain_id = module.params.get('domain_id')
|
||||||
|
remote_ids = module.params.get('remote_ids')
|
||||||
|
|
||||||
|
attributes = {}
|
||||||
|
|
||||||
|
if (description is not None) and (description != idp.description):
|
||||||
|
attributes['description'] = description
|
||||||
|
if (enabled is not None) and (enabled != idp.is_enabled):
|
||||||
|
attributes['enabled'] = enabled
|
||||||
|
if (domain_id is not None) and (domain_id != idp.domain_id):
|
||||||
|
attributes['domain_id'] = domain_id
|
||||||
|
if (remote_ids is not None) and (remote_ids != idp.remote_ids):
|
||||||
|
attributes['remote_ids'] = remote_ids
|
||||||
|
|
||||||
|
if not attributes:
|
||||||
|
return False, idp
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return True, None
|
||||||
|
|
||||||
|
try:
|
||||||
|
new_idp = cloud.identity.update_identity_provider(idp, **attributes)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to update identity provider: {0}'.format(str(ex)))
|
||||||
|
return (True, new_idp)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" Module entry point """
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True, aliases=['id']),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
description=dict(),
|
||||||
|
domain_id=dict(),
|
||||||
|
enabled=dict(type='bool', aliases=['is_enabled']),
|
||||||
|
remote_ids=dict(type='list', elements='str'),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
)
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
name = module.params.get('name')
|
||||||
|
state = module.params.get('state')
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module, min_version="0.44")
|
||||||
|
|
||||||
|
try:
|
||||||
|
idp = cloud.identity.get_identity_provider(name)
|
||||||
|
except sdk.exceptions.ResourceNotFound:
|
||||||
|
idp = None
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to get identity provider: {0}'.format(str(ex)))
|
||||||
|
|
||||||
|
if state == 'absent':
|
||||||
|
if idp is not None:
|
||||||
|
changed = delete_identity_provider(module, sdk, cloud, idp)
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
# state == 'present'
|
||||||
|
else:
|
||||||
|
if idp is None:
|
||||||
|
if module.params.get('domain_id') is None:
|
||||||
|
module.fail_json(msg='A domain_id must be passed when creating'
|
||||||
|
' an identity provider')
|
||||||
|
(changed, idp) = create_identity_provider(module, sdk, cloud, name)
|
||||||
|
idp = normalize_idp(idp)
|
||||||
|
module.exit_json(changed=changed, identity_provider=idp)
|
||||||
|
|
||||||
|
(changed, new_idp) = update_identity_provider(module, sdk, cloud, idp)
|
||||||
|
new_idp = normalize_idp(new_idp)
|
||||||
|
module.exit_json(changed=changed, identity_provider=new_idp)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
107
plugins/modules/federation_idp_info.py
Normal file
107
plugins/modules/federation_idp_info.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: federation_idp_info
|
||||||
|
short_description: Get the information about the available federation identity
|
||||||
|
providers
|
||||||
|
author:
|
||||||
|
- "Mark Chappell (@tremble) <mchappel@redhat.com>"
|
||||||
|
description:
|
||||||
|
- Fetch a federation identity provider.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the identity provider to fetch.
|
||||||
|
- If I(name) is specified, the module will return failed if the identity
|
||||||
|
provider doesn't exist.
|
||||||
|
type: str
|
||||||
|
aliases: ['id']
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk >= 0.44"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Fetch a specific identity provider
|
||||||
|
openstack.cloud.federation_idp_info:
|
||||||
|
cloud: example_cloud
|
||||||
|
name: example_provider
|
||||||
|
|
||||||
|
- name: Fetch all providers
|
||||||
|
openstack.cloud.federation_idp_info:
|
||||||
|
cloud: example_cloud
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_module_kwargs
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_cloud_from_module
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_idp(idp):
|
||||||
|
"""
|
||||||
|
Normalizes the IDP definitions so that the outputs are consistent with the
|
||||||
|
parameters
|
||||||
|
|
||||||
|
- "enabled" (parameter) == "is_enabled" (SDK)
|
||||||
|
- "name" (parameter) == "id" (SDK)
|
||||||
|
"""
|
||||||
|
if idp is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
_idp = idp.to_dict()
|
||||||
|
_idp['enabled'] = idp['is_enabled']
|
||||||
|
_idp['name'] = idp['id']
|
||||||
|
return _idp
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" Module entry point """
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(aliases=['id']),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
)
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
name = module.params.get('name')
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module, min_version="0.44")
|
||||||
|
|
||||||
|
if name:
|
||||||
|
try:
|
||||||
|
idp = normalize_idp(cloud.identity.get_identity_provider(name))
|
||||||
|
except sdk.exceptions.ResourceNotFound:
|
||||||
|
module.fail_json(msg='Failed to find identity provider')
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to get identity provider: {0}'.format(str(ex)))
|
||||||
|
module.exit_json(changed=False, identity_providers=[idp])
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
providers = list(map(normalize_idp, cloud.identity.identity_providers()))
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to list identity providers: {0}'.format(str(ex)))
|
||||||
|
module.exit_json(changed=False, identity_providers=providers)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
224
plugins/modules/federation_mapping.py
Normal file
224
plugins/modules/federation_mapping.py
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: federation_mapping
|
||||||
|
short_description: Manage a federation mapping
|
||||||
|
author:
|
||||||
|
- "Mark Chappell (@tremble) <mchappel@redhat.com>"
|
||||||
|
description:
|
||||||
|
- Manage a federation mapping.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the mapping to manage.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
aliases: ['id']
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Whether the mapping should be C(present) or C(absent).
|
||||||
|
choices: ['present', 'absent']
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
rules:
|
||||||
|
description:
|
||||||
|
- The rules that comprise the mapping. These are pairs of I(local) and
|
||||||
|
I(remote) definitions. For more details on how these work please see
|
||||||
|
the OpenStack documentation
|
||||||
|
U(https://docs.openstack.org/keystone/latest/admin/federation/mapping_combinations.html).
|
||||||
|
- Required if I(state=present)
|
||||||
|
type: list
|
||||||
|
elements: dict
|
||||||
|
suboptions:
|
||||||
|
local:
|
||||||
|
description:
|
||||||
|
- Information on what local attributes will be mapped.
|
||||||
|
required: true
|
||||||
|
type: list
|
||||||
|
elements: dict
|
||||||
|
remote:
|
||||||
|
description:
|
||||||
|
- Information on what remote attributes will be mapped.
|
||||||
|
required: true
|
||||||
|
type: list
|
||||||
|
elements: dict
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk >= 0.44"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Create a new mapping
|
||||||
|
openstack.cloud.federation_mapping:
|
||||||
|
cloud: example_cloud
|
||||||
|
name: example_mapping
|
||||||
|
rules:
|
||||||
|
- local:
|
||||||
|
- user:
|
||||||
|
name: '{0}'
|
||||||
|
- group:
|
||||||
|
id: '0cd5e9'
|
||||||
|
remote:
|
||||||
|
- type: UserName
|
||||||
|
- type: orgPersonType
|
||||||
|
any_one_of:
|
||||||
|
- Contractor
|
||||||
|
- SubContractor
|
||||||
|
|
||||||
|
- name: Delete a mapping
|
||||||
|
openstack.cloud.federation_mapping:
|
||||||
|
name: example_mapping
|
||||||
|
state: absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_module_kwargs
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_cloud_from_module
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_mapping(mapping):
|
||||||
|
"""
|
||||||
|
Normalizes the mapping definitions so that the outputs are consistent with
|
||||||
|
the parameters
|
||||||
|
|
||||||
|
- "name" (parameter) == "id" (SDK)
|
||||||
|
"""
|
||||||
|
if mapping is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
_mapping = mapping.to_dict()
|
||||||
|
_mapping['name'] = mapping['id']
|
||||||
|
return _mapping
|
||||||
|
|
||||||
|
|
||||||
|
def create_mapping(module, sdk, cloud, name):
|
||||||
|
"""
|
||||||
|
Attempt to create a Mapping
|
||||||
|
|
||||||
|
returns: A tuple containing the "Changed" state and the created mapping
|
||||||
|
"""
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return (True, None)
|
||||||
|
|
||||||
|
rules = module.params.get('rules')
|
||||||
|
|
||||||
|
try:
|
||||||
|
mapping = cloud.identity.create_mapping(id=name, rules=rules)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to create mapping: {0}'.format(str(ex)))
|
||||||
|
return (True, mapping)
|
||||||
|
|
||||||
|
|
||||||
|
def delete_mapping(module, sdk, cloud, mapping):
|
||||||
|
"""
|
||||||
|
Attempt to delete a Mapping
|
||||||
|
|
||||||
|
returns: the "Changed" state
|
||||||
|
"""
|
||||||
|
if mapping is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
cloud.identity.delete_mapping(mapping)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to delete mapping: {0}'.format(str(ex)))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def update_mapping(module, sdk, cloud, mapping):
|
||||||
|
"""
|
||||||
|
Attempt to delete a Mapping
|
||||||
|
|
||||||
|
returns: The "Changed" state and the the new mapping
|
||||||
|
"""
|
||||||
|
|
||||||
|
current_rules = mapping.rules
|
||||||
|
new_rules = module.params.get('rules')
|
||||||
|
|
||||||
|
# Nothing to do
|
||||||
|
if current_rules == new_rules:
|
||||||
|
return (False, mapping)
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return (True, None)
|
||||||
|
|
||||||
|
try:
|
||||||
|
new_mapping = cloud.identity.update_mapping(mapping, rules=new_rules)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to update mapping: {0}'.format(str(ex)))
|
||||||
|
return (True, new_mapping)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" Module entry point """
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True, aliases=['id']),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
rules=dict(type='list', elements='dict', options=dict(
|
||||||
|
local=dict(required=True, type='list', elements='dict'),
|
||||||
|
remote=dict(required=True, type='list', elements='dict')
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
required_if=[('state', 'present', ['rules'])]
|
||||||
|
)
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
name = module.params.get('name')
|
||||||
|
state = module.params.get('state')
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module, min_version="0.44")
|
||||||
|
|
||||||
|
try:
|
||||||
|
mapping = cloud.identity.get_mapping(name)
|
||||||
|
except sdk.exceptions.ResourceNotFound:
|
||||||
|
mapping = None
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to fetch mapping: {0}'.format(str(ex)))
|
||||||
|
|
||||||
|
if state == 'absent':
|
||||||
|
if mapping is not None:
|
||||||
|
changed = delete_mapping(module, sdk, cloud, mapping)
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
# state == 'present'
|
||||||
|
else:
|
||||||
|
if len(module.params.get('rules')) < 1:
|
||||||
|
module.fail_json(msg='At least one rule must be passed')
|
||||||
|
|
||||||
|
if mapping is None:
|
||||||
|
(changed, mapping) = create_mapping(module, sdk, cloud, name)
|
||||||
|
mapping = normalize_mapping(mapping)
|
||||||
|
module.exit_json(changed=changed, mapping=mapping)
|
||||||
|
else:
|
||||||
|
(changed, new_mapping) = update_mapping(module, sdk, cloud, mapping)
|
||||||
|
new_mapping = normalize_mapping(new_mapping)
|
||||||
|
module.exit_json(mapping=new_mapping, changed=changed)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
104
plugins/modules/federation_mapping_info.py
Normal file
104
plugins/modules/federation_mapping_info.py
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: federation_mapping_info
|
||||||
|
short_description: Get the information about the available federation mappings
|
||||||
|
author:
|
||||||
|
- "Mark Chappell (@tremble) <mchappel@redhat.com>"
|
||||||
|
description:
|
||||||
|
- Fetch a federation mapping.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the mapping to fetch.
|
||||||
|
- If I(name) is specified, the module will return failed if the mapping
|
||||||
|
doesn't exist.
|
||||||
|
type: str
|
||||||
|
aliases: ['id']
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk >= 0.44"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Fetch a specific mapping
|
||||||
|
openstack.cloud.federation_mapping_info:
|
||||||
|
cloud: example_cloud
|
||||||
|
name: example_mapping
|
||||||
|
|
||||||
|
- name: Fetch all mappings
|
||||||
|
openstack.cloud.federation_mapping_info:
|
||||||
|
cloud: example_cloud
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_module_kwargs
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_cloud_from_module
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_mapping(mapping):
|
||||||
|
"""
|
||||||
|
Normalizes the mapping definitions so that the outputs are consistent with the
|
||||||
|
parameters
|
||||||
|
|
||||||
|
- "name" (parameter) == "id" (SDK)
|
||||||
|
"""
|
||||||
|
if mapping is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
_mapping = mapping.to_dict()
|
||||||
|
_mapping['name'] = mapping['id']
|
||||||
|
return _mapping
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" Module entry point """
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(aliases=['id']),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
)
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
name = module.params.get('name')
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module, min_version="0.44")
|
||||||
|
|
||||||
|
if name:
|
||||||
|
try:
|
||||||
|
mapping = normalize_mapping(cloud.identity.get_mapping(name))
|
||||||
|
except sdk.exceptions.ResourceNotFound:
|
||||||
|
module.fail_json(msg='Failed to find mapping')
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to get mapping: {0}'.format(str(ex)))
|
||||||
|
module.exit_json(changed=False, mappings=[mapping])
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
mappings = list(map(normalize_mapping, cloud.identity.mappings()))
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to list mappings: {0}'.format(str(ex)))
|
||||||
|
module.exit_json(changed=False, mappings=mappings)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
261
plugins/modules/floating_ip.py
Normal file
261
plugins/modules/floating_ip.py
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright: (c) 2015, Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: floating_ip
|
||||||
|
author: Davide Guerri (@dguerri) <davide.guerri@hp.com>
|
||||||
|
short_description: Add/Remove floating IP from an instance
|
||||||
|
description:
|
||||||
|
- Add or Remove a floating IP to an instance.
|
||||||
|
- Returns the floating IP when attaching only if I(wait=true).
|
||||||
|
options:
|
||||||
|
server:
|
||||||
|
description:
|
||||||
|
- The name or ID of the instance to which the IP address
|
||||||
|
should be assigned.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
network:
|
||||||
|
description:
|
||||||
|
- The name or ID of a neutron external network or a nova pool name.
|
||||||
|
type: str
|
||||||
|
floating_ip_address:
|
||||||
|
description:
|
||||||
|
- A floating IP address to attach or to detach. Required only if I(state)
|
||||||
|
is absent. When I(state) is present can be used to specify a IP address
|
||||||
|
to attach.
|
||||||
|
type: str
|
||||||
|
reuse:
|
||||||
|
description:
|
||||||
|
- When I(state) is present, and I(floating_ip_address) is not present,
|
||||||
|
this parameter can be used to specify whether we should try to reuse
|
||||||
|
a floating IP address already allocated to the project.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
fixed_address:
|
||||||
|
description:
|
||||||
|
- To which fixed IP of server the floating IP address should be
|
||||||
|
attached to.
|
||||||
|
type: str
|
||||||
|
nat_destination:
|
||||||
|
description:
|
||||||
|
- The name or id of a neutron private network that the fixed IP to
|
||||||
|
attach floating IP is on
|
||||||
|
aliases: ["fixed_network", "internal_network"]
|
||||||
|
type: str
|
||||||
|
wait:
|
||||||
|
description:
|
||||||
|
- When attaching a floating IP address, specify whether to wait for it to appear as attached.
|
||||||
|
- Must be set to C(yes) for the module to return the value of the floating IP.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
timeout:
|
||||||
|
description:
|
||||||
|
- Time to wait for an IP address to appear as attached. See wait.
|
||||||
|
required: false
|
||||||
|
default: 60
|
||||||
|
type: int
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
purge:
|
||||||
|
description:
|
||||||
|
- When I(state) is absent, indicates whether or not to delete the floating
|
||||||
|
IP completely, or only detach it from the server. Default is to detach only.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Assign a floating IP to the fist interface of `cattle001` from an exiting
|
||||||
|
# external network or nova pool. A new floating IP from the first available
|
||||||
|
# external network is allocated to the project.
|
||||||
|
- openstack.cloud.floating_ip:
|
||||||
|
cloud: dguerri
|
||||||
|
server: cattle001
|
||||||
|
|
||||||
|
# Assign a new floating IP to the instance fixed ip `192.0.2.3` of
|
||||||
|
# `cattle001`. If a free floating IP is already allocated to the project, it is
|
||||||
|
# reused; if not, a new one is created.
|
||||||
|
- openstack.cloud.floating_ip:
|
||||||
|
cloud: dguerri
|
||||||
|
state: present
|
||||||
|
reuse: yes
|
||||||
|
server: cattle001
|
||||||
|
network: ext_net
|
||||||
|
fixed_address: 192.0.2.3
|
||||||
|
wait: true
|
||||||
|
timeout: 180
|
||||||
|
|
||||||
|
# Assign a new floating IP from the network `ext_net` to the instance fixed
|
||||||
|
# ip in network `private_net` of `cattle001`.
|
||||||
|
- openstack.cloud.floating_ip:
|
||||||
|
cloud: dguerri
|
||||||
|
state: present
|
||||||
|
server: cattle001
|
||||||
|
network: ext_net
|
||||||
|
nat_destination: private_net
|
||||||
|
wait: true
|
||||||
|
timeout: 180
|
||||||
|
|
||||||
|
# Detach a floating IP address from a server
|
||||||
|
- openstack.cloud.floating_ip:
|
||||||
|
cloud: dguerri
|
||||||
|
state: absent
|
||||||
|
floating_ip_address: 203.0.113.2
|
||||||
|
server: cattle001
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule, remove_values
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_floating_ip(cloud, floating_ip_address):
|
||||||
|
f_ips = cloud.search_floating_ips(
|
||||||
|
filters={'floating_ip_address': floating_ip_address})
|
||||||
|
if not f_ips:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return f_ips[0]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
server=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
network=dict(required=False, default=None),
|
||||||
|
floating_ip_address=dict(required=False, default=None),
|
||||||
|
reuse=dict(required=False, type='bool', default=False),
|
||||||
|
fixed_address=dict(required=False, default=None),
|
||||||
|
nat_destination=dict(required=False, default=None,
|
||||||
|
aliases=['fixed_network', 'internal_network']),
|
||||||
|
wait=dict(required=False, type='bool', default=False),
|
||||||
|
timeout=dict(required=False, type='int', default=60),
|
||||||
|
purge=dict(required=False, type='bool', default=False),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
server_name_or_id = module.params['server']
|
||||||
|
state = module.params['state']
|
||||||
|
network = module.params['network']
|
||||||
|
floating_ip_address = module.params['floating_ip_address']
|
||||||
|
reuse = module.params['reuse']
|
||||||
|
fixed_address = module.params['fixed_address']
|
||||||
|
nat_destination = module.params['nat_destination']
|
||||||
|
wait = module.params['wait']
|
||||||
|
timeout = module.params['timeout']
|
||||||
|
purge = module.params['purge']
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
|
||||||
|
server = cloud.get_server(server_name_or_id)
|
||||||
|
if server is None:
|
||||||
|
module.fail_json(
|
||||||
|
msg="server {0} not found".format(server_name_or_id))
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
# If f_ip already assigned to server, check that it matches
|
||||||
|
# requirements.
|
||||||
|
public_ip = cloud.get_server_public_ip(server)
|
||||||
|
f_ip = _get_floating_ip(cloud, public_ip) if public_ip else public_ip
|
||||||
|
if f_ip:
|
||||||
|
if network:
|
||||||
|
network_id = cloud.get_network(name_or_id=network)["id"]
|
||||||
|
else:
|
||||||
|
network_id = None
|
||||||
|
# check if we have floating ip on given nat_destination network
|
||||||
|
if nat_destination:
|
||||||
|
nat_floating_addrs = [
|
||||||
|
addr for addr in server.addresses.get(
|
||||||
|
cloud.get_network(nat_destination)['name'], [])
|
||||||
|
if addr['addr'] == public_ip
|
||||||
|
and addr['OS-EXT-IPS:type'] == 'floating'
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(nat_floating_addrs) == 0:
|
||||||
|
module.fail_json(msg="server {server} already has a "
|
||||||
|
"floating-ip on a different "
|
||||||
|
"nat-destination than '{nat_destination}'"
|
||||||
|
.format(server=server_name_or_id,
|
||||||
|
nat_destination=nat_destination))
|
||||||
|
|
||||||
|
if all([fixed_address, f_ip.fixed_ip_address == fixed_address,
|
||||||
|
network, f_ip.network != network_id]):
|
||||||
|
# Current state definitely conflicts with requirements
|
||||||
|
module.fail_json(msg="server {server} already has a "
|
||||||
|
"floating-ip on requested "
|
||||||
|
"interface but it doesn't match "
|
||||||
|
"requested network {network}: {fip}"
|
||||||
|
.format(server=server_name_or_id,
|
||||||
|
network=network,
|
||||||
|
fip=remove_values(f_ip,
|
||||||
|
module.no_log_values)))
|
||||||
|
if not network or f_ip.network == network_id:
|
||||||
|
# Requirements are met
|
||||||
|
module.exit_json(changed=False, floating_ip=f_ip)
|
||||||
|
|
||||||
|
# Requirements are vague enough to ignore existing f_ip and try
|
||||||
|
# to create a new f_ip to the server.
|
||||||
|
|
||||||
|
server = cloud.add_ips_to_server(
|
||||||
|
server=server, ips=floating_ip_address, ip_pool=network,
|
||||||
|
reuse=reuse, fixed_address=fixed_address, wait=wait,
|
||||||
|
timeout=timeout, nat_destination=nat_destination)
|
||||||
|
fip_address = cloud.get_server_public_ip(server)
|
||||||
|
# Update the floating IP status
|
||||||
|
f_ip = _get_floating_ip(cloud, fip_address)
|
||||||
|
module.exit_json(changed=True, floating_ip=f_ip)
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if floating_ip_address is None:
|
||||||
|
if not server_name_or_id:
|
||||||
|
module.fail_json(msg="either server or floating_ip_address are required")
|
||||||
|
server = cloud.get_server(server_name_or_id)
|
||||||
|
floating_ip_address = cloud.get_server_public_ip(server)
|
||||||
|
|
||||||
|
f_ip = _get_floating_ip(cloud, floating_ip_address)
|
||||||
|
|
||||||
|
if not f_ip:
|
||||||
|
# Nothing to detach
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
changed = False
|
||||||
|
if f_ip["fixed_ip_address"]:
|
||||||
|
cloud.detach_ip_from_server(
|
||||||
|
server_id=server['id'], floating_ip_id=f_ip['id'])
|
||||||
|
# Update the floating IP status
|
||||||
|
f_ip = cloud.get_floating_ip(id=f_ip['id'])
|
||||||
|
changed = True
|
||||||
|
if purge:
|
||||||
|
cloud.delete_floating_ip(f_ip['id'])
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
module.exit_json(changed=changed, floating_ip=f_ip)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
106
plugins/modules/group_assignment.py
Normal file
106
plugins/modules/group_assignment.py
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: group_assignment
|
||||||
|
short_description: Associate OpenStack Identity users and groups
|
||||||
|
author: "Monty Taylor (@emonty)"
|
||||||
|
description:
|
||||||
|
- Add and remove users from groups
|
||||||
|
options:
|
||||||
|
user:
|
||||||
|
description:
|
||||||
|
- Name or id for the user
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
group:
|
||||||
|
description:
|
||||||
|
- Name or id for the group.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the user be present or absent in the group
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Add the demo user to the demo group
|
||||||
|
- openstack.cloud.group_assignment:
|
||||||
|
cloud: mycloud
|
||||||
|
user: demo
|
||||||
|
group: demo
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(state, in_group):
|
||||||
|
if state == 'present' and not in_group:
|
||||||
|
return True
|
||||||
|
if state == 'absent' and in_group:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
user=dict(required=True),
|
||||||
|
group=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
user = module.params['user']
|
||||||
|
group = module.params['group']
|
||||||
|
state = module.params['state']
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
in_group = cloud.is_user_in_group(user, group)
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(state, in_group))
|
||||||
|
|
||||||
|
changed = False
|
||||||
|
if state == 'present':
|
||||||
|
if not in_group:
|
||||||
|
cloud.add_user_to_group(user, group)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if in_group:
|
||||||
|
cloud.remove_user_from_group(user, group)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
224
plugins/modules/host_aggregate.py
Normal file
224
plugins/modules/host_aggregate.py
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright 2016 Jakub Jursa <jakub.jursa1@gmail.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: host_aggregate
|
||||||
|
short_description: Manage OpenStack host aggregates
|
||||||
|
author: "Jakub Jursa (@kuboj)"
|
||||||
|
description:
|
||||||
|
- Create, update, or delete OpenStack host aggregates. If a aggregate
|
||||||
|
with the supplied name already exists, it will be updated with the
|
||||||
|
new name, new availability zone, new metadata and new list of hosts.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description: Name of the aggregate.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
metadata:
|
||||||
|
description: Metadata dict.
|
||||||
|
type: dict
|
||||||
|
availability_zone:
|
||||||
|
description: Availability zone to create aggregate into.
|
||||||
|
type: str
|
||||||
|
hosts:
|
||||||
|
description: List of hosts to set for an aggregate.
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
purge_hosts:
|
||||||
|
description: Whether hosts not in I(hosts) should be removed from the aggregate
|
||||||
|
type: bool
|
||||||
|
default: true
|
||||||
|
state:
|
||||||
|
description: Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a host aggregate
|
||||||
|
- openstack.cloud.host_aggregate:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: db_aggregate
|
||||||
|
hosts:
|
||||||
|
- host1
|
||||||
|
- host2
|
||||||
|
metadata:
|
||||||
|
type: dbcluster
|
||||||
|
|
||||||
|
# Add an additional host to the aggregate
|
||||||
|
- openstack.cloud.host_aggregate:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: db_aggregate
|
||||||
|
hosts:
|
||||||
|
- host3
|
||||||
|
purge_hosts: false
|
||||||
|
metadata:
|
||||||
|
type: dbcluster
|
||||||
|
|
||||||
|
# Delete an aggregate
|
||||||
|
- openstack.cloud.host_aggregate:
|
||||||
|
cloud: mycloud
|
||||||
|
state: absent
|
||||||
|
name: db_aggregate
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _needs_update(module, aggregate):
|
||||||
|
new_metadata = (module.params['metadata'] or {})
|
||||||
|
|
||||||
|
if module.params['availability_zone'] is not None:
|
||||||
|
new_metadata['availability_zone'] = module.params['availability_zone']
|
||||||
|
|
||||||
|
if module.params['name'] != aggregate.name:
|
||||||
|
return True
|
||||||
|
if module.params['hosts'] is not None:
|
||||||
|
if module.params['purge_hosts']:
|
||||||
|
if set(module.params['hosts']) != set(aggregate.hosts):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
intersection = set(module.params['hosts']).intersection(set(aggregate.hosts))
|
||||||
|
if set(module.params['hosts']) != intersection:
|
||||||
|
return True
|
||||||
|
if module.params['availability_zone'] is not None:
|
||||||
|
if module.params['availability_zone'] != aggregate.availability_zone:
|
||||||
|
return True
|
||||||
|
if module.params['metadata'] is not None:
|
||||||
|
if new_metadata != aggregate.metadata:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(module, aggregate):
|
||||||
|
state = module.params['state']
|
||||||
|
if state == 'absent' and aggregate:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if aggregate is None:
|
||||||
|
return True
|
||||||
|
return _needs_update(module, aggregate)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _update_hosts(cloud, aggregate, hosts, purge_hosts):
|
||||||
|
if hosts is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
hosts_to_add = set(hosts) - set(aggregate.hosts)
|
||||||
|
for i in hosts_to_add:
|
||||||
|
cloud.add_host_to_aggregate(aggregate.id, i)
|
||||||
|
|
||||||
|
if not purge_hosts:
|
||||||
|
return
|
||||||
|
|
||||||
|
hosts_to_remove = set(aggregate.hosts) - set(hosts)
|
||||||
|
for i in hosts_to_remove:
|
||||||
|
cloud.remove_host_from_aggregate(aggregate.id, i)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
metadata=dict(required=False, default=None, type='dict'),
|
||||||
|
availability_zone=dict(required=False, default=None),
|
||||||
|
hosts=dict(required=False, default=None, type='list', elements='str'),
|
||||||
|
purge_hosts=dict(default=True, type='bool'),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
name = module.params['name']
|
||||||
|
metadata = module.params['metadata']
|
||||||
|
availability_zone = module.params['availability_zone']
|
||||||
|
hosts = module.params['hosts']
|
||||||
|
purge_hosts = module.params['purge_hosts']
|
||||||
|
state = module.params['state']
|
||||||
|
|
||||||
|
if metadata is not None:
|
||||||
|
metadata.pop('availability_zone', None)
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
aggregates = cloud.search_aggregates(name_or_id=name)
|
||||||
|
|
||||||
|
if len(aggregates) == 1:
|
||||||
|
aggregate = aggregates[0]
|
||||||
|
elif len(aggregates) == 0:
|
||||||
|
aggregate = None
|
||||||
|
else:
|
||||||
|
raise Exception("Should not happen")
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(module, aggregate))
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if aggregate is None:
|
||||||
|
aggregate = cloud.create_aggregate(name=name,
|
||||||
|
availability_zone=availability_zone)
|
||||||
|
_update_hosts(cloud, aggregate, hosts, False)
|
||||||
|
if metadata:
|
||||||
|
cloud.set_aggregate_metadata(aggregate.id, metadata)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
if _needs_update(module, aggregate):
|
||||||
|
if availability_zone is not None:
|
||||||
|
aggregate = cloud.update_aggregate(aggregate.id, name=name,
|
||||||
|
availability_zone=availability_zone)
|
||||||
|
if metadata is not None:
|
||||||
|
metas = metadata
|
||||||
|
for i in (set(aggregate.metadata.keys()) - set(metadata.keys())):
|
||||||
|
if i != 'availability_zone':
|
||||||
|
metas[i] = None
|
||||||
|
cloud.set_aggregate_metadata(aggregate.id, metas)
|
||||||
|
_update_hosts(cloud, aggregate, hosts, purge_hosts)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if aggregate is None:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
_update_hosts(cloud, aggregate, [], True)
|
||||||
|
cloud.delete_aggregate(aggregate.id)
|
||||||
|
changed = True
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
185
plugins/modules/identity_domain.py
Normal file
185
plugins/modules/identity_domain.py
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: identity_domain
|
||||||
|
short_description: Manage OpenStack Identity Domains
|
||||||
|
author:
|
||||||
|
- Monty Taylor (@emonty)
|
||||||
|
- Haneef Ali (@haneefs)
|
||||||
|
description:
|
||||||
|
- Create, update, or delete OpenStack Identity domains. If a domain
|
||||||
|
with the supplied name already exists, it will be updated with the
|
||||||
|
new description and enabled attributes.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the instance
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
description:
|
||||||
|
- Description of the domain
|
||||||
|
type: str
|
||||||
|
enabled:
|
||||||
|
description:
|
||||||
|
- Is the domain enabled
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a domain
|
||||||
|
- openstack.cloud.identity_domain:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: demo
|
||||||
|
description: Demo Domain
|
||||||
|
|
||||||
|
# Delete a domain
|
||||||
|
- openstack.cloud.identity_domain:
|
||||||
|
cloud: mycloud
|
||||||
|
state: absent
|
||||||
|
name: demo
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
domain:
|
||||||
|
description: Dictionary describing the domain.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Domain ID.
|
||||||
|
type: str
|
||||||
|
sample: "474acfe5-be34-494c-b339-50f06aa143e4"
|
||||||
|
name:
|
||||||
|
description: Domain name.
|
||||||
|
type: str
|
||||||
|
sample: "demo"
|
||||||
|
description:
|
||||||
|
description: Domain description.
|
||||||
|
type: str
|
||||||
|
sample: "Demo Domain"
|
||||||
|
enabled:
|
||||||
|
description: Domain description.
|
||||||
|
type: bool
|
||||||
|
sample: True
|
||||||
|
|
||||||
|
id:
|
||||||
|
description: The domain ID.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: str
|
||||||
|
sample: "474acfe5-be34-494c-b339-50f06aa143e4"
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _needs_update(module, domain):
|
||||||
|
if module.params['description'] is not None and \
|
||||||
|
domain.description != module.params['description']:
|
||||||
|
return True
|
||||||
|
if domain.enabled != module.params['enabled']:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(module, domain):
|
||||||
|
state = module.params['state']
|
||||||
|
if state == 'absent' and domain:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if domain is None:
|
||||||
|
return True
|
||||||
|
return _needs_update(module, domain)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
description=dict(default=None),
|
||||||
|
enabled=dict(default=True, type='bool'),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
name = module.params['name']
|
||||||
|
description = module.params['description']
|
||||||
|
enabled = module.params['enabled']
|
||||||
|
state = module.params['state']
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
|
||||||
|
domains = cloud.search_domains(filters=dict(name=name))
|
||||||
|
|
||||||
|
if len(domains) > 1:
|
||||||
|
module.fail_json(msg='Domain name %s is not unique' % name)
|
||||||
|
elif len(domains) == 1:
|
||||||
|
domain = domains[0]
|
||||||
|
else:
|
||||||
|
domain = None
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(module, domain))
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if domain is None:
|
||||||
|
domain = cloud.create_domain(
|
||||||
|
name=name, description=description, enabled=enabled)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
if _needs_update(module, domain):
|
||||||
|
domain = cloud.update_domain(
|
||||||
|
domain.id, name=name, description=description,
|
||||||
|
enabled=enabled)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
module.exit_json(changed=changed, domain=domain, id=domain.id)
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if domain is None:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
cloud.delete_domain(domain.id)
|
||||||
|
changed = True
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
139
plugins/modules/identity_domain_info.py
Normal file
139
plugins/modules/identity_domain_info.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2016 Hewlett-Packard Enterprise Corporation
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: identity_domain_info
|
||||||
|
short_description: Retrieve information about one or more OpenStack domains
|
||||||
|
author: "Ricardo Carrillo Cruz (@rcarrillocruz)"
|
||||||
|
description:
|
||||||
|
- Retrieve information about a one or more OpenStack domains
|
||||||
|
- This module was called C(openstack.cloud.identity_domain_facts) before Ansible 2.9, returning C(ansible_facts).
|
||||||
|
Note that the M(openstack.cloud.identity_domain_info) module no longer returns C(ansible_facts)!
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name or ID of the domain
|
||||||
|
type: str
|
||||||
|
filters:
|
||||||
|
description:
|
||||||
|
- A dictionary of meta data to use for further filtering. Elements of
|
||||||
|
this dictionary may be additional dictionaries.
|
||||||
|
type: dict
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Gather information about previously created domain
|
||||||
|
- openstack.cloud.identity_domain_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
register: result
|
||||||
|
- debug:
|
||||||
|
msg: "{{ result.openstack_domains }}"
|
||||||
|
|
||||||
|
# Gather information about a previously created domain by name
|
||||||
|
- openstack.cloud.identity_domain_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
name: demodomain
|
||||||
|
register: result
|
||||||
|
- debug:
|
||||||
|
msg: "{{ result.openstack_domains }}"
|
||||||
|
|
||||||
|
# Gather information about a previously created domain with filter
|
||||||
|
- openstack.cloud.identity_domain_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
name: demodomain
|
||||||
|
filters:
|
||||||
|
enabled: false
|
||||||
|
register: result
|
||||||
|
- debug:
|
||||||
|
msg: "{{ result.openstack_domains }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
openstack_domains:
|
||||||
|
description: has all the OpenStack information about domains
|
||||||
|
returned: always, but can be null
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description: Name given to the domain.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
description: Description of the domain.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
enabled:
|
||||||
|
description: Flag to indicate if the domain is enabled.
|
||||||
|
returned: success
|
||||||
|
type: bool
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=False, default=None),
|
||||||
|
filters=dict(required=False, type='dict', default=None),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
mutually_exclusive=[
|
||||||
|
['name', 'filters'],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
is_old_facts = module._name == 'openstack.cloud.identity_domain_facts'
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'openstack.cloud.identity_domain_facts' module has been renamed to 'openstack.cloud.identity_domain_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts", version='2.13')
|
||||||
|
|
||||||
|
sdk, opcloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
name = module.params['name']
|
||||||
|
filters = module.params['filters']
|
||||||
|
|
||||||
|
if name:
|
||||||
|
# Let's suppose user is passing domain ID
|
||||||
|
try:
|
||||||
|
domains = opcloud.get_domain(name)
|
||||||
|
except Exception:
|
||||||
|
domains = opcloud.search_domains(filters={'name': name})
|
||||||
|
|
||||||
|
else:
|
||||||
|
domains = opcloud.search_domains(filters)
|
||||||
|
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=dict(
|
||||||
|
openstack_domains=domains))
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, openstack_domains=domains)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
167
plugins/modules/identity_group.py
Normal file
167
plugins/modules/identity_group.py
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2016 IBM
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: identity_group
|
||||||
|
short_description: Manage OpenStack Identity Groups
|
||||||
|
author: "Monty Taylor (@emonty), David Shrewsbury (@Shrews)"
|
||||||
|
description:
|
||||||
|
- Manage OpenStack Identity Groups. Groups can be created, deleted or
|
||||||
|
updated. Only the I(description) value can be updated.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Group name
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
description:
|
||||||
|
- Group description
|
||||||
|
type: str
|
||||||
|
domain_id:
|
||||||
|
description:
|
||||||
|
- Domain id to create the group in if the cloud supports domains.
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a group named "demo"
|
||||||
|
- openstack.cloud.identity_group:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: demo
|
||||||
|
description: "Demo Group"
|
||||||
|
domain_id: demoid
|
||||||
|
|
||||||
|
# Update the description on existing "demo" group
|
||||||
|
- openstack.cloud.identity_group:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: demo
|
||||||
|
description: "Something else"
|
||||||
|
domain_id: demoid
|
||||||
|
|
||||||
|
# Delete group named "demo"
|
||||||
|
- openstack.cloud.identity_group:
|
||||||
|
cloud: mycloud
|
||||||
|
state: absent
|
||||||
|
name: demo
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
group:
|
||||||
|
description: Dictionary describing the group.
|
||||||
|
returned: On success when I(state) is 'present'.
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique group ID
|
||||||
|
type: str
|
||||||
|
sample: "ee6156ff04c645f481a6738311aea0b0"
|
||||||
|
name:
|
||||||
|
description: Group name
|
||||||
|
type: str
|
||||||
|
sample: "demo"
|
||||||
|
description:
|
||||||
|
description: Group description
|
||||||
|
type: str
|
||||||
|
sample: "Demo Group"
|
||||||
|
domain_id:
|
||||||
|
description: Domain for the group
|
||||||
|
type: str
|
||||||
|
sample: "default"
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(state, description, group):
|
||||||
|
if state == 'present' and not group:
|
||||||
|
return True
|
||||||
|
if state == 'present' and description is not None and group.description != description:
|
||||||
|
return True
|
||||||
|
if state == 'absent' and group:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
description=dict(required=False, default=None),
|
||||||
|
domain_id=dict(required=False, default=None),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
name = module.params.get('name')
|
||||||
|
description = module.params.get('description')
|
||||||
|
state = module.params.get('state')
|
||||||
|
|
||||||
|
domain_id = module.params.pop('domain_id')
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
if domain_id:
|
||||||
|
group = cloud.get_group(name, filters={'domain_id': domain_id})
|
||||||
|
else:
|
||||||
|
group = cloud.get_group(name)
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(state, description, group))
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if group is None:
|
||||||
|
group = cloud.create_group(
|
||||||
|
name=name, description=description, domain=domain_id)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
if description is not None and group.description != description:
|
||||||
|
group = cloud.update_group(
|
||||||
|
group.id, description=description)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
module.exit_json(changed=changed, group=group)
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if group is None:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
cloud.delete_group(group.id)
|
||||||
|
changed = True
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
164
plugins/modules/identity_group_info.py
Normal file
164
plugins/modules/identity_group_info.py
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2019, Phillipe Smith <phillipelnx@gmail.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: identity_group_info
|
||||||
|
short_description: Retrieve info about one or more OpenStack groups
|
||||||
|
author: "Phillipe Smith (@phsmith)"
|
||||||
|
description:
|
||||||
|
- Retrieve info about a one or more OpenStack groups.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name or ID of the group.
|
||||||
|
type: str
|
||||||
|
domain:
|
||||||
|
description:
|
||||||
|
- Name or ID of the domain containing the group if the cloud supports domains
|
||||||
|
type: str
|
||||||
|
filters:
|
||||||
|
description:
|
||||||
|
- A dictionary of meta data to use for further filtering. Elements of
|
||||||
|
this dictionary may be additional dictionaries.
|
||||||
|
type: dict
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Gather info about previously created groups
|
||||||
|
- name: gather info
|
||||||
|
hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- name: Gather info about previously created groups
|
||||||
|
openstack.cloud.identity_group_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
register: openstack_groups
|
||||||
|
- debug:
|
||||||
|
var: openstack_groups
|
||||||
|
|
||||||
|
# Gather info about a previously created group by name
|
||||||
|
- name: gather info
|
||||||
|
hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- name: Gather info about a previously created group by name
|
||||||
|
openstack.cloud.identity_group_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
name: demogroup
|
||||||
|
register: openstack_groups
|
||||||
|
- debug:
|
||||||
|
var: openstack_groups
|
||||||
|
|
||||||
|
# Gather info about a previously created group in a specific domain
|
||||||
|
- name: gather info
|
||||||
|
hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- name: Gather info about a previously created group in a specific domain
|
||||||
|
openstack.cloud.identity_group_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
name: demogroup
|
||||||
|
domain: admindomain
|
||||||
|
register: openstack_groups
|
||||||
|
- debug:
|
||||||
|
var: openstack_groups
|
||||||
|
|
||||||
|
# Gather info about a previously created group in a specific domain with filter
|
||||||
|
- name: gather info
|
||||||
|
hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- name: Gather info about a previously created group in a specific domain with filter
|
||||||
|
openstack.cloud.identity_group_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
name: demogroup
|
||||||
|
domain: admindomain
|
||||||
|
filters:
|
||||||
|
enabled: False
|
||||||
|
register: openstack_groups
|
||||||
|
- debug:
|
||||||
|
var: openstack_groups
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
openstack_groups:
|
||||||
|
description: Dictionary describing all the matching groups.
|
||||||
|
returned: always, but can be null
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
name:
|
||||||
|
description: Name given to the group.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
description: Description of the group.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
domain_id:
|
||||||
|
description: Domain ID containing the group (keystone v3 clouds only)
|
||||||
|
returned: success
|
||||||
|
type: bool
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec, openstack_cloud_from_module
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=False, default=None),
|
||||||
|
domain=dict(required=False, default=None),
|
||||||
|
filters=dict(required=False, type='dict', default=None),
|
||||||
|
)
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
|
||||||
|
sdk, opcloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
name = module.params['name']
|
||||||
|
domain = module.params['domain']
|
||||||
|
filters = module.params['filters']
|
||||||
|
|
||||||
|
if domain:
|
||||||
|
try:
|
||||||
|
# We assume admin is passing domain id
|
||||||
|
dom = opcloud.get_domain(domain)['id']
|
||||||
|
domain = dom
|
||||||
|
except Exception:
|
||||||
|
# If we fail, maybe admin is passing a domain name.
|
||||||
|
# Note that domains have unique names, just like id.
|
||||||
|
dom = opcloud.search_domains(filters={'name': domain})
|
||||||
|
if dom:
|
||||||
|
domain = dom[0]['id']
|
||||||
|
else:
|
||||||
|
module.fail_json(msg='Domain name or ID does not exist')
|
||||||
|
|
||||||
|
if not filters:
|
||||||
|
filters = {}
|
||||||
|
|
||||||
|
groups = opcloud.search_groups(name, filters, domain_id=domain)
|
||||||
|
module.exit_json(changed=False, groups=groups)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
125
plugins/modules/identity_role.py
Normal file
125
plugins/modules/identity_role.py
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2016 IBM
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: identity_role
|
||||||
|
short_description: Manage OpenStack Identity Roles
|
||||||
|
author:
|
||||||
|
- Monty Taylor (@emonty)
|
||||||
|
- David Shrewsbury (@Shrews)
|
||||||
|
description:
|
||||||
|
- Manage OpenStack Identity Roles.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Role Name
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a role named "demo"
|
||||||
|
- openstack.cloud.identity_role:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: demo
|
||||||
|
|
||||||
|
# Delete the role named "demo"
|
||||||
|
- openstack.cloud.identity_role:
|
||||||
|
cloud: mycloud
|
||||||
|
state: absent
|
||||||
|
name: demo
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
role:
|
||||||
|
description: Dictionary describing the role.
|
||||||
|
returned: On success when I(state) is 'present'.
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique role ID.
|
||||||
|
type: str
|
||||||
|
sample: "677bfab34c844a01b88a217aa12ec4c2"
|
||||||
|
name:
|
||||||
|
description: Role name.
|
||||||
|
type: str
|
||||||
|
sample: "demo"
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(state, role):
|
||||||
|
if state == 'present' and not role:
|
||||||
|
return True
|
||||||
|
if state == 'absent' and role:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
name = module.params.get('name')
|
||||||
|
state = module.params.get('state')
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
role = cloud.get_role(name)
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(state, role))
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if role is None:
|
||||||
|
role = cloud.create_role(name)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
module.exit_json(changed=changed, role=role)
|
||||||
|
elif state == 'absent':
|
||||||
|
if role is None:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
cloud.delete_role(name)
|
||||||
|
changed = True
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
299
plugins/modules/identity_user.py
Normal file
299
plugins/modules/identity_user.py
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: identity_user
|
||||||
|
short_description: Manage OpenStack Identity Users
|
||||||
|
author: David Shrewsbury (@Shrews)
|
||||||
|
description:
|
||||||
|
- Manage OpenStack Identity users. Users can be created,
|
||||||
|
updated or deleted using this module. A user will be updated
|
||||||
|
if I(name) matches an existing user and I(state) is present.
|
||||||
|
The value for I(name) cannot be updated without deleting and
|
||||||
|
re-creating the user.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Username for the user
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
password:
|
||||||
|
description:
|
||||||
|
- Password for the user
|
||||||
|
type: str
|
||||||
|
update_password:
|
||||||
|
required: false
|
||||||
|
choices: ['always', 'on_create']
|
||||||
|
description:
|
||||||
|
- C(always) will attempt to update password. C(on_create) will only
|
||||||
|
set the password for newly created users.
|
||||||
|
type: str
|
||||||
|
email:
|
||||||
|
description:
|
||||||
|
- Email address for the user
|
||||||
|
type: str
|
||||||
|
description:
|
||||||
|
description:
|
||||||
|
- Description about the user
|
||||||
|
type: str
|
||||||
|
default_project:
|
||||||
|
description:
|
||||||
|
- Project name or ID that the user should be associated with by default
|
||||||
|
type: str
|
||||||
|
domain:
|
||||||
|
description:
|
||||||
|
- Domain to create the user in if the cloud supports domains
|
||||||
|
type: str
|
||||||
|
enabled:
|
||||||
|
description:
|
||||||
|
- Is the user enabled
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a user
|
||||||
|
- openstack.cloud.identity_user:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: demouser
|
||||||
|
password: secret
|
||||||
|
email: demo@example.com
|
||||||
|
domain: default
|
||||||
|
default_project: demo
|
||||||
|
|
||||||
|
# Delete a user
|
||||||
|
- openstack.cloud.identity_user:
|
||||||
|
cloud: mycloud
|
||||||
|
state: absent
|
||||||
|
name: demouser
|
||||||
|
|
||||||
|
# Create a user but don't update password if user exists
|
||||||
|
- openstack.cloud.identity_user:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: demouser
|
||||||
|
password: secret
|
||||||
|
update_password: on_create
|
||||||
|
email: demo@example.com
|
||||||
|
domain: default
|
||||||
|
default_project: demo
|
||||||
|
|
||||||
|
# Create a user without password
|
||||||
|
- openstack.cloud.identity_user:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: demouser
|
||||||
|
email: demo@example.com
|
||||||
|
domain: default
|
||||||
|
default_project: demo
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
user:
|
||||||
|
description: Dictionary describing the user.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
default_project_id:
|
||||||
|
description: User default project ID. Only present with Keystone >= v3.
|
||||||
|
type: str
|
||||||
|
sample: "4427115787be45f08f0ec22a03bfc735"
|
||||||
|
domain_id:
|
||||||
|
description: User domain ID. Only present with Keystone >= v3.
|
||||||
|
type: str
|
||||||
|
sample: "default"
|
||||||
|
email:
|
||||||
|
description: User email address
|
||||||
|
type: str
|
||||||
|
sample: "demo@example.com"
|
||||||
|
id:
|
||||||
|
description: User ID
|
||||||
|
type: str
|
||||||
|
sample: "f59382db809c43139982ca4189404650"
|
||||||
|
name:
|
||||||
|
description: User name
|
||||||
|
type: str
|
||||||
|
sample: "demouser"
|
||||||
|
'''
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _needs_update(params_dict, user):
|
||||||
|
for k in params_dict:
|
||||||
|
if k not in ('password', 'update_password') and user[k] != params_dict[k]:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# We don't get password back in the user object, so assume any supplied
|
||||||
|
# password is a change.
|
||||||
|
if (
|
||||||
|
params_dict['password'] is not None
|
||||||
|
and params_dict['update_password'] == 'always'
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _get_domain_id(cloud, domain):
|
||||||
|
try:
|
||||||
|
# We assume admin is passing domain id
|
||||||
|
domain_id = cloud.get_domain(domain)['id']
|
||||||
|
except Exception:
|
||||||
|
# If we fail, maybe admin is passing a domain name.
|
||||||
|
# Note that domains have unique names, just like id.
|
||||||
|
try:
|
||||||
|
domain_id = cloud.search_domains(filters={'name': domain})[0]['id']
|
||||||
|
except Exception:
|
||||||
|
# Ok, let's hope the user is non-admin and passing a sane id
|
||||||
|
domain_id = domain
|
||||||
|
|
||||||
|
return domain_id
|
||||||
|
|
||||||
|
|
||||||
|
def _get_default_project_id(cloud, default_project, domain_id, module):
|
||||||
|
project = cloud.get_project(default_project, domain_id=domain_id)
|
||||||
|
if not project:
|
||||||
|
module.fail_json(msg='Default project %s is not valid' % default_project)
|
||||||
|
|
||||||
|
return project['id']
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
password=dict(required=False, default=None, no_log=True),
|
||||||
|
email=dict(required=False, default=None),
|
||||||
|
default_project=dict(required=False, default=None),
|
||||||
|
description=dict(type='str'),
|
||||||
|
domain=dict(required=False, default=None),
|
||||||
|
enabled=dict(default=True, type='bool'),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
update_password=dict(default=None, choices=['always', 'on_create']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
name = module.params['name']
|
||||||
|
password = module.params.get('password')
|
||||||
|
email = module.params['email']
|
||||||
|
default_project = module.params['default_project']
|
||||||
|
domain = module.params['domain']
|
||||||
|
enabled = module.params['enabled']
|
||||||
|
state = module.params['state']
|
||||||
|
update_password = module.params['update_password']
|
||||||
|
description = module.params['description']
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
domain_id = None
|
||||||
|
if domain:
|
||||||
|
domain_id = _get_domain_id(cloud, domain)
|
||||||
|
user = cloud.get_user(name, domain_id=domain_id)
|
||||||
|
else:
|
||||||
|
user = cloud.get_user(name)
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if update_password in ('always', 'on_create'):
|
||||||
|
if not password:
|
||||||
|
msg = "update_password is %s but a password value is missing" % update_password
|
||||||
|
module.fail_json(msg=msg)
|
||||||
|
default_project_id = None
|
||||||
|
if default_project:
|
||||||
|
default_project_id = _get_default_project_id(cloud, default_project, domain_id, module)
|
||||||
|
|
||||||
|
if user is None:
|
||||||
|
if description is not None:
|
||||||
|
user = cloud.create_user(
|
||||||
|
name=name, password=password, email=email,
|
||||||
|
default_project=default_project_id, domain_id=domain_id,
|
||||||
|
enabled=enabled, description=description)
|
||||||
|
else:
|
||||||
|
user = cloud.create_user(
|
||||||
|
name=name, password=password, email=email,
|
||||||
|
default_project=default_project_id, domain_id=domain_id,
|
||||||
|
enabled=enabled)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
params_dict = {'email': email, 'enabled': enabled,
|
||||||
|
'password': password,
|
||||||
|
'update_password': update_password}
|
||||||
|
if description is not None:
|
||||||
|
params_dict['description'] = description
|
||||||
|
if domain_id is not None:
|
||||||
|
params_dict['domain_id'] = domain_id
|
||||||
|
if default_project_id is not None:
|
||||||
|
params_dict['default_project_id'] = default_project_id
|
||||||
|
|
||||||
|
if _needs_update(params_dict, user):
|
||||||
|
if update_password == 'always':
|
||||||
|
if description is not None:
|
||||||
|
user = cloud.update_user(
|
||||||
|
user['id'], password=password, email=email,
|
||||||
|
default_project=default_project_id,
|
||||||
|
domain_id=domain_id, enabled=enabled, description=description)
|
||||||
|
else:
|
||||||
|
user = cloud.update_user(
|
||||||
|
user['id'], password=password, email=email,
|
||||||
|
default_project=default_project_id,
|
||||||
|
domain_id=domain_id, enabled=enabled)
|
||||||
|
else:
|
||||||
|
if description is not None:
|
||||||
|
user = cloud.update_user(
|
||||||
|
user['id'], email=email,
|
||||||
|
default_project=default_project_id,
|
||||||
|
domain_id=domain_id, enabled=enabled, description=description)
|
||||||
|
else:
|
||||||
|
user = cloud.update_user(
|
||||||
|
user['id'], email=email,
|
||||||
|
default_project=default_project_id,
|
||||||
|
domain_id=domain_id, enabled=enabled)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
module.exit_json(changed=changed, user=user)
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if user is None:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
if domain:
|
||||||
|
cloud.delete_user(user['id'], domain_id=domain_id)
|
||||||
|
else:
|
||||||
|
cloud.delete_user(user['id'])
|
||||||
|
changed = True
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
174
plugins/modules/identity_user_info.py
Normal file
174
plugins/modules/identity_user_info.py
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright (c) 2016 Hewlett-Packard Enterprise Corporation
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: identity_user_info
|
||||||
|
short_description: Retrieve information about one or more OpenStack users
|
||||||
|
author: "Ricardo Carrillo Cruz (@rcarrillocruz)"
|
||||||
|
description:
|
||||||
|
- Retrieve information about a one or more OpenStack users
|
||||||
|
- This module was called C(openstack.cloud.identity_user_facts) before Ansible 2.9, returning C(ansible_facts).
|
||||||
|
Note that the M(openstack.cloud.identity_user_info) module no longer returns C(ansible_facts)!
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name or ID of the user
|
||||||
|
type: str
|
||||||
|
domain:
|
||||||
|
description:
|
||||||
|
- Name or ID of the domain containing the user if the cloud supports domains
|
||||||
|
type: str
|
||||||
|
filters:
|
||||||
|
description:
|
||||||
|
- A dictionary of meta data to use for further filtering. Elements of
|
||||||
|
this dictionary may be additional dictionaries.
|
||||||
|
type: dict
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Gather information about previously created users
|
||||||
|
- openstack.cloud.identity_user_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
register: result
|
||||||
|
- debug:
|
||||||
|
msg: "{{ result.openstack_users }}"
|
||||||
|
|
||||||
|
# Gather information about a previously created user by name
|
||||||
|
- openstack.cloud.identity_user_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
name: demouser
|
||||||
|
register: result
|
||||||
|
- debug:
|
||||||
|
msg: "{{ result.openstack_users }}"
|
||||||
|
|
||||||
|
# Gather information about a previously created user in a specific domain
|
||||||
|
- openstack.cloud.identity_user_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
name: demouser
|
||||||
|
domain: admindomain
|
||||||
|
register: result
|
||||||
|
- debug:
|
||||||
|
msg: "{{ result.openstack_users }}"
|
||||||
|
|
||||||
|
# Gather information about a previously created user in a specific domain with filter
|
||||||
|
- openstack.cloud.identity_user_info:
|
||||||
|
cloud: awesomecloud
|
||||||
|
name: demouser
|
||||||
|
domain: admindomain
|
||||||
|
filters:
|
||||||
|
enabled: False
|
||||||
|
register: result
|
||||||
|
- debug:
|
||||||
|
msg: "{{ result.openstack_users }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
openstack_users:
|
||||||
|
description: has all the OpenStack information about users
|
||||||
|
returned: always, but can be null
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description: Name given to the user.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
enabled:
|
||||||
|
description: Flag to indicate if the user is enabled
|
||||||
|
returned: success
|
||||||
|
type: bool
|
||||||
|
domain_id:
|
||||||
|
description: Domain ID containing the user
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
default_project_id:
|
||||||
|
description: Default project ID of the user
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
email:
|
||||||
|
description: Email of the user
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
username:
|
||||||
|
description: Username of the user
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (
|
||||||
|
openstack_full_argument_spec,
|
||||||
|
openstack_cloud_from_module,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=False, default=None),
|
||||||
|
domain=dict(required=False, default=None),
|
||||||
|
filters=dict(required=False, type='dict', default=None),
|
||||||
|
)
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name == 'openstack.cloud.identity_user_facts'
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'openstack.cloud.identity_user_facts' module has been renamed to 'openstack.cloud.identity_user_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts", version='2.13')
|
||||||
|
|
||||||
|
sdk, opcloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
name = module.params['name']
|
||||||
|
domain = module.params['domain']
|
||||||
|
filters = module.params['filters']
|
||||||
|
|
||||||
|
if domain:
|
||||||
|
try:
|
||||||
|
# We assume admin is passing domain id
|
||||||
|
dom = opcloud.get_domain(domain)['id']
|
||||||
|
domain = dom
|
||||||
|
except Exception:
|
||||||
|
# If we fail, maybe admin is passing a domain name.
|
||||||
|
# Note that domains have unique names, just like id.
|
||||||
|
dom = opcloud.search_domains(filters={'name': domain})
|
||||||
|
if dom:
|
||||||
|
domain = dom[0]['id']
|
||||||
|
else:
|
||||||
|
module.fail_json(msg='Domain name or ID does not exist')
|
||||||
|
|
||||||
|
if not filters:
|
||||||
|
filters = {}
|
||||||
|
|
||||||
|
filters['domain_id'] = domain
|
||||||
|
|
||||||
|
users = opcloud.search_users(name, filters)
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=dict(
|
||||||
|
openstack_users=users))
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, openstack_users=users)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
246
plugins/modules/image.py
Normal file
246
plugins/modules/image.py
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# Copyright (c) 2013, Benno Joy <benno@ansible.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
# TODO(mordred): we need to support "location"(v1) and "locations"(v2)
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: image
|
||||||
|
short_description: Add/Delete images from OpenStack Cloud
|
||||||
|
author: "Monty Taylor (@emonty)"
|
||||||
|
description:
|
||||||
|
- Add or Remove images from the OpenStack Image Repository
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the image when uploading - or the name/ID of the image if deleting
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
id:
|
||||||
|
description:
|
||||||
|
- The ID of the image when uploading an image
|
||||||
|
type: str
|
||||||
|
checksum:
|
||||||
|
description:
|
||||||
|
- The checksum of the image
|
||||||
|
type: str
|
||||||
|
disk_format:
|
||||||
|
description:
|
||||||
|
- The format of the disk that is getting uploaded
|
||||||
|
default: qcow2
|
||||||
|
choices: ['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso', 'vhdx', 'ploop']
|
||||||
|
type: str
|
||||||
|
container_format:
|
||||||
|
description:
|
||||||
|
- The format of the container
|
||||||
|
default: bare
|
||||||
|
choices: ['ami', 'aki', 'ari', 'bare', 'ovf', 'ova', 'docker']
|
||||||
|
type: str
|
||||||
|
owner:
|
||||||
|
description:
|
||||||
|
- The owner of the image
|
||||||
|
type: str
|
||||||
|
min_disk:
|
||||||
|
description:
|
||||||
|
- The minimum disk space (in GB) required to boot this image
|
||||||
|
type: int
|
||||||
|
min_ram:
|
||||||
|
description:
|
||||||
|
- The minimum ram (in MB) required to boot this image
|
||||||
|
type: int
|
||||||
|
is_public:
|
||||||
|
description:
|
||||||
|
- Whether the image can be accessed publicly. Note that publicizing an image requires admin role by default.
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
protected:
|
||||||
|
description:
|
||||||
|
- Prevent image from being deleted
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
filename:
|
||||||
|
description:
|
||||||
|
- The path to the file which has to be uploaded
|
||||||
|
type: str
|
||||||
|
ramdisk:
|
||||||
|
description:
|
||||||
|
- The name of an existing ramdisk image that will be associated with this image
|
||||||
|
type: str
|
||||||
|
kernel:
|
||||||
|
description:
|
||||||
|
- The name of an existing kernel image that will be associated with this image
|
||||||
|
type: str
|
||||||
|
properties:
|
||||||
|
description:
|
||||||
|
- Additional properties to be associated with this image
|
||||||
|
default: {}
|
||||||
|
type: dict
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
volume:
|
||||||
|
description:
|
||||||
|
- ID of a volume to create an image from.
|
||||||
|
- The volume must be in AVAILABLE state.
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Upload an image from a local file named cirros-0.3.0-x86_64-disk.img
|
||||||
|
- openstack.cloud.image:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: admin
|
||||||
|
password: passme
|
||||||
|
project_name: admin
|
||||||
|
openstack.cloud.identity_user_domain_name: Default
|
||||||
|
openstack.cloud.project_domain_name: Default
|
||||||
|
name: cirros
|
||||||
|
container_format: bare
|
||||||
|
disk_format: qcow2
|
||||||
|
state: present
|
||||||
|
filename: cirros-0.3.0-x86_64-disk.img
|
||||||
|
kernel: cirros-vmlinuz
|
||||||
|
ramdisk: cirros-initrd
|
||||||
|
properties:
|
||||||
|
cpu_arch: x86_64
|
||||||
|
distro: ubuntu
|
||||||
|
|
||||||
|
# Create image from volume attached to an instance
|
||||||
|
- name: create volume snapshot
|
||||||
|
openstack.cloud.volume_snapshot:
|
||||||
|
auth:
|
||||||
|
"{{ auth }}"
|
||||||
|
display_name: myvol_snapshot
|
||||||
|
volume: myvol
|
||||||
|
force: yes
|
||||||
|
register: myvol_snapshot
|
||||||
|
|
||||||
|
- name: create volume from snapshot
|
||||||
|
openstack.cloud.volume:
|
||||||
|
auth:
|
||||||
|
"{{ auth }}"
|
||||||
|
size: "{{ myvol_snapshot.snapshot.size }}"
|
||||||
|
snapshot_id: "{{ myvol_snapshot.snapshot.id }}"
|
||||||
|
display_name: myvol_snapshot_volume
|
||||||
|
wait: yes
|
||||||
|
register: myvol_snapshot_volume
|
||||||
|
|
||||||
|
- name: create image from volume snapshot
|
||||||
|
openstack.cloud.image:
|
||||||
|
auth:
|
||||||
|
"{{ auth }}"
|
||||||
|
volume: "{{ myvol_snapshot_volume.volume.id }}"
|
||||||
|
name: myvol_image
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
id=dict(default=None),
|
||||||
|
checksum=dict(default=None),
|
||||||
|
disk_format=dict(default='qcow2', choices=['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso', 'vhdx', 'ploop']),
|
||||||
|
container_format=dict(default='bare', choices=['ami', 'aki', 'ari', 'bare', 'ovf', 'ova', 'docker']),
|
||||||
|
owner=dict(default=None),
|
||||||
|
min_disk=dict(type='int', default=0),
|
||||||
|
min_ram=dict(type='int', default=0),
|
||||||
|
is_public=dict(type='bool', default=False),
|
||||||
|
protected=dict(type='bool', default=False),
|
||||||
|
filename=dict(default=None),
|
||||||
|
ramdisk=dict(default=None),
|
||||||
|
kernel=dict(default=None),
|
||||||
|
properties=dict(type='dict', default={}),
|
||||||
|
volume=dict(default=None),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
mutually_exclusive=[['filename', 'volume']],
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
|
||||||
|
changed = False
|
||||||
|
if module.params['id']:
|
||||||
|
image = cloud.get_image(name_or_id=module.params['id'])
|
||||||
|
elif module.params['checksum']:
|
||||||
|
image = cloud.get_image(name_or_id=module.params['name'], filters={'checksum': module.params['checksum']})
|
||||||
|
else:
|
||||||
|
image = cloud.get_image(name_or_id=module.params['name'])
|
||||||
|
|
||||||
|
if module.params['state'] == 'present':
|
||||||
|
if not image:
|
||||||
|
kwargs = {}
|
||||||
|
if module.params['id'] is not None:
|
||||||
|
kwargs['id'] = module.params['id']
|
||||||
|
image = cloud.create_image(
|
||||||
|
name=module.params['name'],
|
||||||
|
filename=module.params['filename'],
|
||||||
|
disk_format=module.params['disk_format'],
|
||||||
|
container_format=module.params['container_format'],
|
||||||
|
wait=module.params['wait'],
|
||||||
|
timeout=module.params['timeout'],
|
||||||
|
is_public=module.params['is_public'],
|
||||||
|
protected=module.params['protected'],
|
||||||
|
min_disk=module.params['min_disk'],
|
||||||
|
min_ram=module.params['min_ram'],
|
||||||
|
volume=module.params['volume'],
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
changed = True
|
||||||
|
if not module.params['wait']:
|
||||||
|
module.exit_json(changed=changed, image=image, id=image.id)
|
||||||
|
|
||||||
|
cloud.update_image_properties(
|
||||||
|
image=image,
|
||||||
|
kernel=module.params['kernel'],
|
||||||
|
ramdisk=module.params['ramdisk'],
|
||||||
|
protected=module.params['protected'],
|
||||||
|
**module.params['properties'])
|
||||||
|
image = cloud.get_image(name_or_id=image.id)
|
||||||
|
module.exit_json(changed=changed, image=image, id=image.id)
|
||||||
|
|
||||||
|
elif module.params['state'] == 'absent':
|
||||||
|
if not image:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
cloud.delete_image(
|
||||||
|
name_or_id=module.params['name'],
|
||||||
|
wait=module.params['wait'],
|
||||||
|
timeout=module.params['timeout'])
|
||||||
|
changed = True
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
192
plugins/modules/image_info.py
Normal file
192
plugins/modules/image_info.py
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
module: image_info
|
||||||
|
short_description: Retrieve information about an image within OpenStack.
|
||||||
|
author: "Davide Agnello (@dagnello)"
|
||||||
|
description:
|
||||||
|
- Retrieve information about a image image from OpenStack.
|
||||||
|
- This module was called C(openstack.cloud.image_facts) before Ansible 2.9, returning C(ansible_facts).
|
||||||
|
Note that the M(openstack.cloud.image_info) module no longer returns C(ansible_facts)!
|
||||||
|
options:
|
||||||
|
image:
|
||||||
|
description:
|
||||||
|
- Name or ID of the image
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
properties:
|
||||||
|
description:
|
||||||
|
- Dict of properties of the images used for query
|
||||||
|
type: dict
|
||||||
|
required: false
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Gather information about a previously created image named image1
|
||||||
|
openstack.cloud.image_info:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: user
|
||||||
|
password: password
|
||||||
|
project_name: someproject
|
||||||
|
image: image1
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Show openstack information
|
||||||
|
debug:
|
||||||
|
msg: "{{ result.openstack_image }}"
|
||||||
|
|
||||||
|
# Show all available Openstack images
|
||||||
|
- name: Retrieve all available Openstack images
|
||||||
|
openstack.cloud.image_info:
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Show images
|
||||||
|
debug:
|
||||||
|
msg: "{{ result.openstack_image }}"
|
||||||
|
|
||||||
|
# Show images matching requested properties
|
||||||
|
- name: Retrieve images having properties with desired values
|
||||||
|
openstack.cloud.image_facts:
|
||||||
|
properties:
|
||||||
|
some_property: some_value
|
||||||
|
OtherProp: OtherVal
|
||||||
|
|
||||||
|
- name: Show images
|
||||||
|
debug:
|
||||||
|
msg: "{{ result.openstack_image }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
openstack_image:
|
||||||
|
description: has all the openstack information about the image
|
||||||
|
returned: always, but can be null
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description: Name given to the image.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
status:
|
||||||
|
description: Image status.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
created_at:
|
||||||
|
description: Image created at timestamp.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
deleted:
|
||||||
|
description: Image deleted flag.
|
||||||
|
returned: success
|
||||||
|
type: bool
|
||||||
|
container_format:
|
||||||
|
description: Container format of the image.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
min_ram:
|
||||||
|
description: Min amount of RAM required for this image.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
disk_format:
|
||||||
|
description: Disk format of the image.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
updated_at:
|
||||||
|
description: Image updated at timestamp.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
properties:
|
||||||
|
description: Additional properties associated with the image.
|
||||||
|
returned: success
|
||||||
|
type: dict
|
||||||
|
min_disk:
|
||||||
|
description: Min amount of disk space required for this image.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
protected:
|
||||||
|
description: Image protected flag.
|
||||||
|
returned: success
|
||||||
|
type: bool
|
||||||
|
checksum:
|
||||||
|
description: Checksum for the image.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
owner:
|
||||||
|
description: Owner for the image.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
is_public:
|
||||||
|
description: Is public flag of the image.
|
||||||
|
returned: success
|
||||||
|
type: bool
|
||||||
|
deleted_at:
|
||||||
|
description: Image deleted at timestamp.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
size:
|
||||||
|
description: Size of the image.
|
||||||
|
returned: success
|
||||||
|
type: int
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
image=dict(required=False),
|
||||||
|
properties=dict(default=None, type='dict'),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
is_old_facts = module._name == 'openstack.cloud.image_facts'
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'openstack.cloud.image_facts' module has been renamed to 'openstack.cloud.image_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts", version='2.13')
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
if module.params['image']:
|
||||||
|
image = cloud.get_image(module.params['image'])
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=dict(
|
||||||
|
openstack_image=image))
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, openstack_image=image)
|
||||||
|
else:
|
||||||
|
images = cloud.search_images(filters=module.params['properties'])
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=dict(
|
||||||
|
openstack_image=images))
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, openstack_image=images)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
167
plugins/modules/keypair.py
Normal file
167
plugins/modules/keypair.py
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||||
|
# Copyright (c) 2013, Benno Joy <benno@ansible.com>
|
||||||
|
# Copyright (c) 2013, John Dewey <john@dewey.ws>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: keypair
|
||||||
|
short_description: Add/Delete a keypair from OpenStack
|
||||||
|
author: "Benno Joy (@bennojoy)"
|
||||||
|
description:
|
||||||
|
- Add or Remove key pair from OpenStack
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the key pair
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
public_key:
|
||||||
|
description:
|
||||||
|
- The public key that would be uploaded to nova and injected into VMs
|
||||||
|
upon creation.
|
||||||
|
type: str
|
||||||
|
public_key_file:
|
||||||
|
description:
|
||||||
|
- Path to local file containing ssh public key. Mutually exclusive
|
||||||
|
with public_key.
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent. If state is replace and
|
||||||
|
the key exists but has different content, delete it and recreate it
|
||||||
|
with the new content.
|
||||||
|
choices: [present, absent, replace]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Creates a key pair with the running users public key
|
||||||
|
- openstack.cloud.keypair:
|
||||||
|
cloud: mordred
|
||||||
|
state: present
|
||||||
|
name: ansible_key
|
||||||
|
public_key_file: /home/me/.ssh/id_rsa.pub
|
||||||
|
|
||||||
|
# Creates a new key pair and the private key returned after the run.
|
||||||
|
- openstack.cloud.keypair:
|
||||||
|
cloud: rax-dfw
|
||||||
|
state: present
|
||||||
|
name: ansible_key
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description: Name given to the keypair.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
public_key:
|
||||||
|
description: The public key value for the keypair.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
private_key:
|
||||||
|
description: The private key value for the keypair.
|
||||||
|
returned: Only when a keypair is generated for the user (e.g., when creating one
|
||||||
|
and a public key is not specified).
|
||||||
|
type: str
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _system_state_change(module, keypair):
|
||||||
|
state = module.params['state']
|
||||||
|
if state == 'present' and not keypair:
|
||||||
|
return True
|
||||||
|
if state == 'absent' and keypair:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
public_key=dict(default=None),
|
||||||
|
public_key_file=dict(default=None),
|
||||||
|
state=dict(default='present',
|
||||||
|
choices=['absent', 'present', 'replace']),
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
mutually_exclusive=[['public_key', 'public_key_file']])
|
||||||
|
|
||||||
|
module = AnsibleModule(argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs)
|
||||||
|
|
||||||
|
state = module.params['state']
|
||||||
|
name = module.params['name']
|
||||||
|
public_key = module.params['public_key']
|
||||||
|
|
||||||
|
if module.params['public_key_file']:
|
||||||
|
with open(module.params['public_key_file']) as public_key_fh:
|
||||||
|
public_key = public_key_fh.read().rstrip()
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
keypair = cloud.get_keypair(name)
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
module.exit_json(changed=_system_state_change(module, keypair))
|
||||||
|
|
||||||
|
if state in ('present', 'replace'):
|
||||||
|
if keypair and keypair['name'] == name:
|
||||||
|
if public_key and (public_key != keypair['public_key']):
|
||||||
|
if state == 'present':
|
||||||
|
module.fail_json(
|
||||||
|
msg="Key name %s present but key hash not the same"
|
||||||
|
" as offered. Delete key first." % name
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cloud.delete_keypair(name)
|
||||||
|
keypair = cloud.create_keypair(name, public_key)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
keypair = cloud.create_keypair(name, public_key)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
module.exit_json(changed=changed,
|
||||||
|
key=keypair,
|
||||||
|
id=keypair['id'])
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if keypair:
|
||||||
|
cloud.delete_keypair(name)
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
217
plugins/modules/keystone_federation_protocol.py
Normal file
217
plugins/modules/keystone_federation_protocol.py
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: keystone_federation_protocol
|
||||||
|
short_description: manage a federation Protocol
|
||||||
|
author:
|
||||||
|
- "Mark Chappell (@tremble) <mchappel@redhat.com>"
|
||||||
|
description:
|
||||||
|
- Manage a federation Protocol.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the Protocol.
|
||||||
|
type: str
|
||||||
|
required: true
|
||||||
|
aliases: ['id']
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Whether the protocol should be C(present) or C(absent).
|
||||||
|
choices: ['present', 'absent']
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
idp_id:
|
||||||
|
description:
|
||||||
|
- The name of the Identity Provider this Protocol is associated with.
|
||||||
|
aliases: ['idp_name']
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
mapping_id:
|
||||||
|
description:
|
||||||
|
- The name of the Mapping to use for this Protocol.'
|
||||||
|
- Required when creating a new Protocol.
|
||||||
|
type: str
|
||||||
|
aliases: ['mapping_name']
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk >= 0.44"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Create a protocol
|
||||||
|
openstack.cloud.keystone_federation_protocol:
|
||||||
|
cloud: example_cloud
|
||||||
|
name: example_protocol
|
||||||
|
idp_id: example_idp
|
||||||
|
mapping_id: example_mapping
|
||||||
|
|
||||||
|
- name: Delete a protocol
|
||||||
|
openstack.cloud.keystone_federation_protocol:
|
||||||
|
cloud: example_cloud
|
||||||
|
name: example_protocol
|
||||||
|
idp_id: example_idp
|
||||||
|
state: absent
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_module_kwargs
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_cloud_from_module
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_protocol(protocol):
|
||||||
|
"""
|
||||||
|
Normalizes the protocol definitions so that the outputs are consistent with the
|
||||||
|
parameters
|
||||||
|
|
||||||
|
- "name" (parameter) == "id" (SDK)
|
||||||
|
"""
|
||||||
|
if protocol is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
_protocol = protocol.to_dict()
|
||||||
|
_protocol['name'] = protocol['id']
|
||||||
|
# As of 0.44 SDK doesn't copy the URI parameters over, so let's add them
|
||||||
|
_protocol['idp_id'] = protocol['idp_id']
|
||||||
|
return _protocol
|
||||||
|
|
||||||
|
|
||||||
|
def delete_protocol(module, sdk, cloud, protocol):
|
||||||
|
"""
|
||||||
|
Delete an existing Protocol
|
||||||
|
|
||||||
|
returns: the "Changed" state
|
||||||
|
"""
|
||||||
|
|
||||||
|
if protocol is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
cloud.identity.delete_federation_protocol(None, protocol)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to delete protocol: {0}'.format(str(ex)))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def create_protocol(module, sdk, cloud, name):
|
||||||
|
"""
|
||||||
|
Create a new Protocol
|
||||||
|
|
||||||
|
returns: the "Changed" state and the new protocol
|
||||||
|
"""
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return True, None
|
||||||
|
|
||||||
|
idp_name = module.params.get('idp_id')
|
||||||
|
mapping_id = module.params.get('mapping_id')
|
||||||
|
|
||||||
|
attributes = {
|
||||||
|
'idp_id': idp_name,
|
||||||
|
'mapping_id': mapping_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
protocol = cloud.identity.create_federation_protocol(id=name, **attributes)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to create protocol: {0}'.format(str(ex)))
|
||||||
|
return (True, protocol)
|
||||||
|
|
||||||
|
|
||||||
|
def update_protocol(module, sdk, cloud, protocol):
|
||||||
|
"""
|
||||||
|
Update an existing Protocol
|
||||||
|
|
||||||
|
returns: the "Changed" state and the new protocol
|
||||||
|
"""
|
||||||
|
|
||||||
|
mapping_id = module.params.get('mapping_id')
|
||||||
|
|
||||||
|
attributes = {}
|
||||||
|
|
||||||
|
if (mapping_id is not None) and (mapping_id != protocol.mapping_id):
|
||||||
|
attributes['mapping_id'] = mapping_id
|
||||||
|
|
||||||
|
if not attributes:
|
||||||
|
return False, protocol
|
||||||
|
|
||||||
|
if module.check_mode:
|
||||||
|
return True, None
|
||||||
|
|
||||||
|
try:
|
||||||
|
new_protocol = cloud.identity.update_federation_protocol(None, protocol, **attributes)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to update protocol: {0}'.format(str(ex)))
|
||||||
|
return (True, new_protocol)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" Module entry point """
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True, aliases=['id']),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
idp_id=dict(required=True, aliases=['idp_name']),
|
||||||
|
mapping_id=dict(aliases=['mapping_name']),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
)
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
name = module.params.get('name')
|
||||||
|
state = module.params.get('state')
|
||||||
|
idp = module.params.get('idp_id')
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module, min_version="0.44")
|
||||||
|
|
||||||
|
try:
|
||||||
|
protocol = cloud.identity.get_federation_protocol(idp, name)
|
||||||
|
except sdk.exceptions.ResourceNotFound:
|
||||||
|
protocol = None
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to get protocol: {0}'.format(str(ex)))
|
||||||
|
|
||||||
|
if state == 'absent':
|
||||||
|
if protocol is not None:
|
||||||
|
changed = delete_protocol(module, sdk, cloud, protocol)
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
|
||||||
|
# state == 'present'
|
||||||
|
else:
|
||||||
|
if protocol is None:
|
||||||
|
if module.params.get('mapping_id') is None:
|
||||||
|
module.fail_json(msg='A mapping_id must be passed when creating'
|
||||||
|
' a protocol')
|
||||||
|
(changed, protocol) = create_protocol(module, sdk, cloud, name)
|
||||||
|
protocol = normalize_protocol(protocol)
|
||||||
|
module.exit_json(changed=changed, protocol=protocol)
|
||||||
|
|
||||||
|
else:
|
||||||
|
(changed, new_protocol) = update_protocol(module, sdk, cloud, protocol)
|
||||||
|
new_protocol = normalize_protocol(new_protocol)
|
||||||
|
module.exit_json(changed=changed, protocol=new_protocol)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
116
plugins/modules/keystone_federation_protocol_info.py
Normal file
116
plugins/modules/keystone_federation_protocol_info.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# Copyright: Ansible Project
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: keystone_federation_protocol_info
|
||||||
|
short_description: get information about federation Protocols
|
||||||
|
author:
|
||||||
|
- "Mark Chappell (@tremble) <mchappel@redhat.com>"
|
||||||
|
description:
|
||||||
|
- Get information about federation Protocols.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The name of the Protocol.
|
||||||
|
type: str
|
||||||
|
aliases: ['id']
|
||||||
|
idp_id:
|
||||||
|
description:
|
||||||
|
- The name of the Identity Provider this Protocol is associated with.
|
||||||
|
aliases: ['idp_name']
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk >= 0.44"
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Describe a protocol
|
||||||
|
openstack.cloud.keystone_federation_protocol_info:
|
||||||
|
cloud: example_cloud
|
||||||
|
name: example_protocol
|
||||||
|
idp_id: example_idp
|
||||||
|
mapping_name: example_mapping
|
||||||
|
|
||||||
|
- name: Describe all protocols attached to an IDP
|
||||||
|
openstack.cloud.keystone_federation_protocol_info:
|
||||||
|
cloud: example_cloud
|
||||||
|
idp_id: example_idp
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_module_kwargs
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_cloud_from_module
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_protocol(protocol):
|
||||||
|
"""
|
||||||
|
Normalizes the protocol definitions so that the outputs are consistent with the
|
||||||
|
parameters
|
||||||
|
|
||||||
|
- "name" (parameter) == "id" (SDK)
|
||||||
|
"""
|
||||||
|
if protocol is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
_protocol = protocol.to_dict()
|
||||||
|
_protocol['name'] = protocol['id']
|
||||||
|
# As of 0.44 SDK doesn't copy the URI parameters over, so let's add them
|
||||||
|
_protocol['idp_id'] = protocol['idp_id']
|
||||||
|
return _protocol
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
""" Module entry point """
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(aliases=['id']),
|
||||||
|
idp_id=dict(required=True, aliases=['idp_name']),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
)
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec,
|
||||||
|
supports_check_mode=True,
|
||||||
|
**module_kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
name = module.params.get('name')
|
||||||
|
idp = module.params.get('idp_id')
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module, min_version="0.44")
|
||||||
|
|
||||||
|
if name:
|
||||||
|
try:
|
||||||
|
protocol = cloud.identity.get_federation_protocol(idp, name)
|
||||||
|
protocol = normalize_protocol(protocol)
|
||||||
|
except sdk.exceptions.ResourceNotFound:
|
||||||
|
module.fail_json(msg='Failed to find protocol')
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to get protocol: {0}'.format(str(ex)))
|
||||||
|
module.exit_json(changed=False, protocols=[protocol])
|
||||||
|
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
protocols = list(map(normalize_protocol, cloud.identity.federation_protocols(idp)))
|
||||||
|
except sdk.exceptions.OpenStackCloudException as ex:
|
||||||
|
module.fail_json(msg='Failed to list protocols: {0}'.format(str(ex)))
|
||||||
|
module.exit_json(changed=False, protocols=protocols)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
260
plugins/modules/lb_listener.py
Normal file
260
plugins/modules/lb_listener.py
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2018 Catalyst Cloud Ltd.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: lb_listener
|
||||||
|
short_description: Add/Delete a listener for a load balancer from OpenStack Cloud
|
||||||
|
author: "Lingxian Kong (@lingxiankong)"
|
||||||
|
description:
|
||||||
|
- Add or Remove a listener for a load balancer from the OpenStack load-balancer service.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the listener
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
loadbalancer:
|
||||||
|
description:
|
||||||
|
- The name or id of the load balancer that this listener belongs to.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
protocol:
|
||||||
|
description:
|
||||||
|
- The protocol for the listener.
|
||||||
|
choices: [HTTP, HTTPS, TCP, TERMINATED_HTTPS]
|
||||||
|
default: HTTP
|
||||||
|
type: str
|
||||||
|
protocol_port:
|
||||||
|
description:
|
||||||
|
- The protocol port number for the listener.
|
||||||
|
default: 80
|
||||||
|
type: int
|
||||||
|
wait:
|
||||||
|
description:
|
||||||
|
- If the module should wait for the load balancer to be ACTIVE.
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
timeout:
|
||||||
|
description:
|
||||||
|
- The amount of time the module should wait for the load balancer to get
|
||||||
|
into ACTIVE state.
|
||||||
|
default: 180
|
||||||
|
type: int
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
id:
|
||||||
|
description: The listener UUID.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
listener:
|
||||||
|
description: Dictionary describing the listener.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
name:
|
||||||
|
description: Name given to the listener.
|
||||||
|
type: str
|
||||||
|
sample: "test"
|
||||||
|
description:
|
||||||
|
description: The listener description.
|
||||||
|
type: str
|
||||||
|
sample: "description"
|
||||||
|
load_balancer_id:
|
||||||
|
description: The load balancer UUID this listener belongs to.
|
||||||
|
type: str
|
||||||
|
sample: "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"
|
||||||
|
loadbalancers:
|
||||||
|
description: A list of load balancer IDs..
|
||||||
|
type: list
|
||||||
|
sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}]
|
||||||
|
provisioning_status:
|
||||||
|
description: The provisioning status of the listener.
|
||||||
|
type: str
|
||||||
|
sample: "ACTIVE"
|
||||||
|
operating_status:
|
||||||
|
description: The operating status of the listener.
|
||||||
|
type: str
|
||||||
|
sample: "ONLINE"
|
||||||
|
is_admin_state_up:
|
||||||
|
description: The administrative state of the listener.
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
protocol:
|
||||||
|
description: The protocol for the listener.
|
||||||
|
type: str
|
||||||
|
sample: "HTTP"
|
||||||
|
protocol_port:
|
||||||
|
description: The protocol port number for the listener.
|
||||||
|
type: int
|
||||||
|
sample: 80
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a listener, wait for the loadbalancer to be active.
|
||||||
|
- openstack.cloud.lb_listener:
|
||||||
|
cloud: mycloud
|
||||||
|
endpoint_type: admin
|
||||||
|
state: present
|
||||||
|
name: test-listener
|
||||||
|
loadbalancer: test-loadbalancer
|
||||||
|
protocol: HTTP
|
||||||
|
protocol_port: 8080
|
||||||
|
|
||||||
|
# Create a listener, do not wait for the loadbalancer to be active.
|
||||||
|
- openstack.cloud.lb_listener:
|
||||||
|
cloud: mycloud
|
||||||
|
endpoint_type: admin
|
||||||
|
state: present
|
||||||
|
name: test-listener
|
||||||
|
loadbalancer: test-loadbalancer
|
||||||
|
protocol: HTTP
|
||||||
|
protocol_port: 8080
|
||||||
|
wait: no
|
||||||
|
|
||||||
|
# Delete a listener
|
||||||
|
- openstack.cloud.lb_listener:
|
||||||
|
cloud: mycloud
|
||||||
|
endpoint_type: admin
|
||||||
|
state: absent
|
||||||
|
name: test-listener
|
||||||
|
loadbalancer: test-loadbalancer
|
||||||
|
'''
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _lb_wait_for_status(module, cloud, lb, status, failures, interval=5):
|
||||||
|
"""Wait for load balancer to be in a particular provisioning status."""
|
||||||
|
timeout = module.params['timeout']
|
||||||
|
|
||||||
|
total_sleep = 0
|
||||||
|
if failures is None:
|
||||||
|
failures = []
|
||||||
|
|
||||||
|
while total_sleep < timeout:
|
||||||
|
lb = cloud.load_balancer.get_load_balancer(lb.id)
|
||||||
|
if lb.provisioning_status == status:
|
||||||
|
return None
|
||||||
|
if lb.provisioning_status in failures:
|
||||||
|
module.fail_json(
|
||||||
|
msg="Load Balancer %s transitioned to failure state %s" %
|
||||||
|
(lb.id, lb.provisioning_status)
|
||||||
|
)
|
||||||
|
|
||||||
|
time.sleep(interval)
|
||||||
|
total_sleep += interval
|
||||||
|
|
||||||
|
module.fail_json(
|
||||||
|
msg="Timeout waiting for Load Balancer %s to transition to %s" %
|
||||||
|
(lb.id, status)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
loadbalancer=dict(required=True),
|
||||||
|
protocol=dict(default='HTTP',
|
||||||
|
choices=['HTTP', 'HTTPS', 'TCP', 'TERMINATED_HTTPS']),
|
||||||
|
protocol_port=dict(default=80, type='int', required=False),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
loadbalancer = module.params['loadbalancer']
|
||||||
|
loadbalancer_id = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
changed = False
|
||||||
|
listener = cloud.load_balancer.find_listener(
|
||||||
|
name_or_id=module.params['name'])
|
||||||
|
|
||||||
|
if module.params['state'] == 'present':
|
||||||
|
if not listener:
|
||||||
|
lb = cloud.load_balancer.find_load_balancer(loadbalancer)
|
||||||
|
if not lb:
|
||||||
|
module.fail_json(
|
||||||
|
msg='load balancer %s is not found' % loadbalancer
|
||||||
|
)
|
||||||
|
loadbalancer_id = lb.id
|
||||||
|
|
||||||
|
listener = cloud.load_balancer.create_listener(
|
||||||
|
name=module.params['name'],
|
||||||
|
loadbalancer_id=loadbalancer_id,
|
||||||
|
protocol=module.params['protocol'],
|
||||||
|
protocol_port=module.params['protocol_port'],
|
||||||
|
)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if not module.params['wait']:
|
||||||
|
module.exit_json(changed=changed,
|
||||||
|
listener=listener.to_dict(),
|
||||||
|
id=listener.id)
|
||||||
|
|
||||||
|
if module.params['wait']:
|
||||||
|
# Check in case the listener already exists.
|
||||||
|
lb = cloud.load_balancer.find_load_balancer(loadbalancer)
|
||||||
|
if not lb:
|
||||||
|
module.fail_json(
|
||||||
|
msg='load balancer %s is not found' % loadbalancer
|
||||||
|
)
|
||||||
|
_lb_wait_for_status(module, cloud, lb, "ACTIVE", ["ERROR"])
|
||||||
|
|
||||||
|
module.exit_json(changed=changed, listener=listener.to_dict(),
|
||||||
|
id=listener.id)
|
||||||
|
elif module.params['state'] == 'absent':
|
||||||
|
if not listener:
|
||||||
|
changed = False
|
||||||
|
else:
|
||||||
|
cloud.load_balancer.delete_listener(listener)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if module.params['wait']:
|
||||||
|
# Wait for the load balancer to be active after deleting
|
||||||
|
# the listener.
|
||||||
|
lb = cloud.load_balancer.find_load_balancer(loadbalancer)
|
||||||
|
if not lb:
|
||||||
|
module.fail_json(
|
||||||
|
msg='load balancer %s is not found' % loadbalancer
|
||||||
|
)
|
||||||
|
_lb_wait_for_status(module, cloud, lb, "ACTIVE", ["ERROR"])
|
||||||
|
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
232
plugins/modules/lb_member.py
Normal file
232
plugins/modules/lb_member.py
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2018 Catalyst Cloud Ltd.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: lb_member
|
||||||
|
short_description: Add/Delete a member for a pool in load balancer from OpenStack Cloud
|
||||||
|
author: "Lingxian Kong (@lingxiankong)"
|
||||||
|
description:
|
||||||
|
- Add or Remove a member for a pool from the OpenStack load-balancer service.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the member
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
pool:
|
||||||
|
description:
|
||||||
|
- The name or id of the pool that this member belongs to.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
protocol_port:
|
||||||
|
description:
|
||||||
|
- The protocol port number for the member.
|
||||||
|
default: 80
|
||||||
|
type: int
|
||||||
|
address:
|
||||||
|
description:
|
||||||
|
- The IP address of the member.
|
||||||
|
type: str
|
||||||
|
subnet_id:
|
||||||
|
description:
|
||||||
|
- The subnet ID the member service is accessible from.
|
||||||
|
type: str
|
||||||
|
wait:
|
||||||
|
description:
|
||||||
|
- If the module should wait for the load balancer to be ACTIVE.
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
timeout:
|
||||||
|
description:
|
||||||
|
- The amount of time the module should wait for the load balancer to get
|
||||||
|
into ACTIVE state.
|
||||||
|
default: 180
|
||||||
|
type: int
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
id:
|
||||||
|
description: The member UUID.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
member:
|
||||||
|
description: Dictionary describing the member.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
name:
|
||||||
|
description: Name given to the member.
|
||||||
|
type: str
|
||||||
|
sample: "test"
|
||||||
|
description:
|
||||||
|
description: The member description.
|
||||||
|
type: str
|
||||||
|
sample: "description"
|
||||||
|
provisioning_status:
|
||||||
|
description: The provisioning status of the member.
|
||||||
|
type: str
|
||||||
|
sample: "ACTIVE"
|
||||||
|
operating_status:
|
||||||
|
description: The operating status of the member.
|
||||||
|
type: str
|
||||||
|
sample: "ONLINE"
|
||||||
|
is_admin_state_up:
|
||||||
|
description: The administrative state of the member.
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
protocol_port:
|
||||||
|
description: The protocol port number for the member.
|
||||||
|
type: int
|
||||||
|
sample: 80
|
||||||
|
subnet_id:
|
||||||
|
description: The subnet ID the member service is accessible from.
|
||||||
|
type: str
|
||||||
|
sample: "489247fa-9c25-11e8-9679-00224d6b7bc1"
|
||||||
|
address:
|
||||||
|
description: The IP address of the backend member server.
|
||||||
|
type: str
|
||||||
|
sample: "192.168.2.10"
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a member, wait for the member to be created.
|
||||||
|
- openstack.cloud.lb_member:
|
||||||
|
cloud: mycloud
|
||||||
|
endpoint_type: admin
|
||||||
|
state: present
|
||||||
|
name: test-member
|
||||||
|
pool: test-pool
|
||||||
|
address: 192.168.10.3
|
||||||
|
protocol_port: 8080
|
||||||
|
|
||||||
|
# Delete a listener
|
||||||
|
- openstack.cloud.lb_member:
|
||||||
|
cloud: mycloud
|
||||||
|
endpoint_type: admin
|
||||||
|
state: absent
|
||||||
|
name: test-member
|
||||||
|
pool: test-pool
|
||||||
|
'''
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _wait_for_member_status(module, cloud, pool_id, member_id, status,
|
||||||
|
failures, interval=5):
|
||||||
|
timeout = module.params['timeout']
|
||||||
|
|
||||||
|
total_sleep = 0
|
||||||
|
if failures is None:
|
||||||
|
failures = []
|
||||||
|
|
||||||
|
while total_sleep < timeout:
|
||||||
|
member = cloud.load_balancer.get_member(member_id, pool_id)
|
||||||
|
provisioning_status = member.provisioning_status
|
||||||
|
if provisioning_status == status:
|
||||||
|
return member
|
||||||
|
if provisioning_status in failures:
|
||||||
|
module.fail_json(
|
||||||
|
msg="Member %s transitioned to failure state %s" %
|
||||||
|
(member_id, provisioning_status)
|
||||||
|
)
|
||||||
|
|
||||||
|
time.sleep(interval)
|
||||||
|
total_sleep += interval
|
||||||
|
|
||||||
|
module.fail_json(
|
||||||
|
msg="Timeout waiting for member %s to transition to %s" %
|
||||||
|
(member_id, status)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
pool=dict(required=True),
|
||||||
|
address=dict(default=None),
|
||||||
|
protocol_port=dict(default=80, type='int'),
|
||||||
|
subnet_id=dict(default=None),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
name = module.params['name']
|
||||||
|
pool = module.params['pool']
|
||||||
|
|
||||||
|
try:
|
||||||
|
changed = False
|
||||||
|
|
||||||
|
pool_ret = cloud.load_balancer.find_pool(name_or_id=pool)
|
||||||
|
if not pool_ret:
|
||||||
|
module.fail_json(msg='pool %s is not found' % pool)
|
||||||
|
|
||||||
|
pool_id = pool_ret.id
|
||||||
|
member = cloud.load_balancer.find_member(name, pool_id)
|
||||||
|
|
||||||
|
if module.params['state'] == 'present':
|
||||||
|
if not member:
|
||||||
|
member = cloud.load_balancer.create_member(
|
||||||
|
pool_ret,
|
||||||
|
address=module.params['address'],
|
||||||
|
name=name,
|
||||||
|
protocol_port=module.params['protocol_port'],
|
||||||
|
subnet_id=module.params['subnet_id']
|
||||||
|
)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if not module.params['wait']:
|
||||||
|
module.exit_json(changed=changed,
|
||||||
|
member=member.to_dict(),
|
||||||
|
id=member.id)
|
||||||
|
|
||||||
|
if module.params['wait']:
|
||||||
|
member = _wait_for_member_status(module, cloud, pool_id,
|
||||||
|
member.id, "ACTIVE",
|
||||||
|
["ERROR"])
|
||||||
|
|
||||||
|
module.exit_json(changed=changed, member=member.to_dict(),
|
||||||
|
id=member.id)
|
||||||
|
|
||||||
|
elif module.params['state'] == 'absent':
|
||||||
|
if member:
|
||||||
|
cloud.load_balancer.delete_member(member, pool_ret)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
271
plugins/modules/lb_pool.py
Normal file
271
plugins/modules/lb_pool.py
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2018 Catalyst Cloud Ltd.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: lb_pool
|
||||||
|
short_description: Add/Delete a pool in the load balancing service from OpenStack Cloud
|
||||||
|
author: "Lingxian Kong (@lingxiankong)"
|
||||||
|
description:
|
||||||
|
- Add or Remove a pool from the OpenStack load-balancer service.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the pool
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
loadbalancer:
|
||||||
|
description:
|
||||||
|
- The name or id of the load balancer that this pool belongs to.
|
||||||
|
Either loadbalancer or listener must be specified for pool creation.
|
||||||
|
type: str
|
||||||
|
listener:
|
||||||
|
description:
|
||||||
|
- The name or id of the listener that this pool belongs to.
|
||||||
|
Either loadbalancer or listener must be specified for pool creation.
|
||||||
|
type: str
|
||||||
|
protocol:
|
||||||
|
description:
|
||||||
|
- The protocol for the pool.
|
||||||
|
choices: [HTTP, HTTPS, PROXY, TCP, UDP]
|
||||||
|
default: HTTP
|
||||||
|
type: str
|
||||||
|
lb_algorithm:
|
||||||
|
description:
|
||||||
|
- The load balancing algorithm for the pool.
|
||||||
|
choices: [LEAST_CONNECTIONS, ROUND_ROBIN, SOURCE_IP]
|
||||||
|
default: ROUND_ROBIN
|
||||||
|
type: str
|
||||||
|
wait:
|
||||||
|
description:
|
||||||
|
- If the module should wait for the pool to be ACTIVE.
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
timeout:
|
||||||
|
description:
|
||||||
|
- The amount of time the module should wait for the pool to get
|
||||||
|
into ACTIVE state.
|
||||||
|
default: 180
|
||||||
|
type: int
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
id:
|
||||||
|
description: The pool UUID.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
listener:
|
||||||
|
description: Dictionary describing the pool.
|
||||||
|
returned: On success when I(state) is 'present'
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
name:
|
||||||
|
description: Name given to the pool.
|
||||||
|
type: str
|
||||||
|
sample: "test"
|
||||||
|
description:
|
||||||
|
description: The pool description.
|
||||||
|
type: str
|
||||||
|
sample: "description"
|
||||||
|
loadbalancers:
|
||||||
|
description: A list of load balancer IDs.
|
||||||
|
type: list
|
||||||
|
sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}]
|
||||||
|
listeners:
|
||||||
|
description: A list of listener IDs.
|
||||||
|
type: list
|
||||||
|
sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}]
|
||||||
|
members:
|
||||||
|
description: A list of member IDs.
|
||||||
|
type: list
|
||||||
|
sample: [{"id": "b32eef7e-d2a6-4ea4-a301-60a873f89b3b"}]
|
||||||
|
loadbalancer_id:
|
||||||
|
description: The load balancer ID the pool belongs to. This field is set when the pool doesn't belong to any listener in the load balancer.
|
||||||
|
type: str
|
||||||
|
sample: "7c4be3f8-9c2f-11e8-83b3-44a8422643a4"
|
||||||
|
listener_id:
|
||||||
|
description: The listener ID the pool belongs to.
|
||||||
|
type: str
|
||||||
|
sample: "956aa716-9c2f-11e8-83b3-44a8422643a4"
|
||||||
|
provisioning_status:
|
||||||
|
description: The provisioning status of the pool.
|
||||||
|
type: str
|
||||||
|
sample: "ACTIVE"
|
||||||
|
operating_status:
|
||||||
|
description: The operating status of the pool.
|
||||||
|
type: str
|
||||||
|
sample: "ONLINE"
|
||||||
|
is_admin_state_up:
|
||||||
|
description: The administrative state of the pool.
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
protocol:
|
||||||
|
description: The protocol for the pool.
|
||||||
|
type: str
|
||||||
|
sample: "HTTP"
|
||||||
|
lb_algorithm:
|
||||||
|
description: The load balancing algorithm for the pool.
|
||||||
|
type: str
|
||||||
|
sample: "ROUND_ROBIN"
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a pool, wait for the pool to be active.
|
||||||
|
- openstack.cloud.lb_pool:
|
||||||
|
cloud: mycloud
|
||||||
|
endpoint_type: admin
|
||||||
|
state: present
|
||||||
|
name: test-pool
|
||||||
|
loadbalancer: test-loadbalancer
|
||||||
|
protocol: HTTP
|
||||||
|
lb_algorithm: ROUND_ROBIN
|
||||||
|
|
||||||
|
# Delete a pool
|
||||||
|
- openstack.cloud.lb_pool:
|
||||||
|
cloud: mycloud
|
||||||
|
endpoint_type: admin
|
||||||
|
state: absent
|
||||||
|
name: test-pool
|
||||||
|
'''
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec, \
|
||||||
|
openstack_module_kwargs, openstack_cloud_from_module
|
||||||
|
|
||||||
|
|
||||||
|
def _wait_for_pool_status(module, cloud, pool_id, status, failures,
|
||||||
|
interval=5):
|
||||||
|
timeout = module.params['timeout']
|
||||||
|
|
||||||
|
total_sleep = 0
|
||||||
|
if failures is None:
|
||||||
|
failures = []
|
||||||
|
|
||||||
|
while total_sleep < timeout:
|
||||||
|
pool = cloud.load_balancer.get_pool(pool_id)
|
||||||
|
provisioning_status = pool.provisioning_status
|
||||||
|
if provisioning_status == status:
|
||||||
|
return pool
|
||||||
|
if provisioning_status in failures:
|
||||||
|
module.fail_json(
|
||||||
|
msg="pool %s transitioned to failure state %s" %
|
||||||
|
(pool_id, provisioning_status)
|
||||||
|
)
|
||||||
|
|
||||||
|
time.sleep(interval)
|
||||||
|
total_sleep += interval
|
||||||
|
|
||||||
|
module.fail_json(
|
||||||
|
msg="timeout waiting for pool %s to transition to %s" %
|
||||||
|
(pool_id, status)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
loadbalancer=dict(default=None),
|
||||||
|
listener=dict(default=None),
|
||||||
|
protocol=dict(default='HTTP',
|
||||||
|
choices=['HTTP', 'HTTPS', 'TCP', 'UDP', 'PROXY']),
|
||||||
|
lb_algorithm=dict(
|
||||||
|
default='ROUND_ROBIN',
|
||||||
|
choices=['ROUND_ROBIN', 'LEAST_CONNECTIONS', 'SOURCE_IP']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs(
|
||||||
|
mutually_exclusive=[['loadbalancer', 'listener']]
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
|
||||||
|
loadbalancer = module.params['loadbalancer']
|
||||||
|
listener = module.params['listener']
|
||||||
|
|
||||||
|
try:
|
||||||
|
changed = False
|
||||||
|
pool = cloud.load_balancer.find_pool(name_or_id=module.params['name'])
|
||||||
|
|
||||||
|
if module.params['state'] == 'present':
|
||||||
|
if not pool:
|
||||||
|
loadbalancer_id = None
|
||||||
|
if not (loadbalancer or listener):
|
||||||
|
module.fail_json(
|
||||||
|
msg="either loadbalancer or listener must be provided"
|
||||||
|
)
|
||||||
|
|
||||||
|
if loadbalancer:
|
||||||
|
lb = cloud.load_balancer.find_load_balancer(loadbalancer)
|
||||||
|
if not lb:
|
||||||
|
module.fail_json(msg='load balancer %s is not '
|
||||||
|
'found' % loadbalancer)
|
||||||
|
loadbalancer_id = lb.id
|
||||||
|
|
||||||
|
listener_id = None
|
||||||
|
if listener:
|
||||||
|
listener_ret = cloud.load_balancer.find_listener(listener)
|
||||||
|
if not listener_ret:
|
||||||
|
module.fail_json(msg='listener %s is not found'
|
||||||
|
% listener)
|
||||||
|
listener_id = listener_ret.id
|
||||||
|
|
||||||
|
pool = cloud.load_balancer.create_pool(
|
||||||
|
name=module.params['name'],
|
||||||
|
loadbalancer_id=loadbalancer_id,
|
||||||
|
listener_id=listener_id,
|
||||||
|
protocol=module.params['protocol'],
|
||||||
|
lb_algorithm=module.params['lb_algorithm']
|
||||||
|
)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if not module.params['wait']:
|
||||||
|
module.exit_json(changed=changed,
|
||||||
|
pool=pool.to_dict(),
|
||||||
|
id=pool.id)
|
||||||
|
|
||||||
|
if module.params['wait']:
|
||||||
|
pool = _wait_for_pool_status(module, cloud, pool.id, "ACTIVE",
|
||||||
|
["ERROR"])
|
||||||
|
|
||||||
|
module.exit_json(changed=changed, pool=pool.to_dict(),
|
||||||
|
id=pool.id)
|
||||||
|
|
||||||
|
elif module.params['state'] == 'absent':
|
||||||
|
if pool:
|
||||||
|
cloud.load_balancer.delete_pool(pool)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
614
plugins/modules/loadbalancer.py
Normal file
614
plugins/modules/loadbalancer.py
Normal file
@ -0,0 +1,614 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2018 Catalyst Cloud Ltd.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: loadbalancer
|
||||||
|
short_description: Add/Delete load balancer from OpenStack Cloud
|
||||||
|
author: "Lingxian Kong (@lingxiankong)"
|
||||||
|
description:
|
||||||
|
- Add or Remove load balancer from the OpenStack load-balancer
|
||||||
|
service(Octavia). Load balancer update is not supported for now.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name that has to be given to the load balancer
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
vip_network:
|
||||||
|
description:
|
||||||
|
- The name or id of the network for the virtual IP of the load balancer.
|
||||||
|
One of I(vip_network), I(vip_subnet), or I(vip_port) must be specified
|
||||||
|
for creation.
|
||||||
|
type: str
|
||||||
|
vip_subnet:
|
||||||
|
description:
|
||||||
|
- The name or id of the subnet for the virtual IP of the load balancer.
|
||||||
|
One of I(vip_network), I(vip_subnet), or I(vip_port) must be specified
|
||||||
|
for creation.
|
||||||
|
type: str
|
||||||
|
vip_port:
|
||||||
|
description:
|
||||||
|
- The name or id of the load balancer virtual IP port. One of
|
||||||
|
I(vip_network), I(vip_subnet), or I(vip_port) must be specified for
|
||||||
|
creation.
|
||||||
|
type: str
|
||||||
|
vip_address:
|
||||||
|
description:
|
||||||
|
- IP address of the load balancer virtual IP.
|
||||||
|
type: str
|
||||||
|
public_ip_address:
|
||||||
|
description:
|
||||||
|
- Public IP address associated with the VIP.
|
||||||
|
type: str
|
||||||
|
auto_public_ip:
|
||||||
|
description:
|
||||||
|
- Allocate a public IP address and associate with the VIP automatically.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
public_network:
|
||||||
|
description:
|
||||||
|
- The name or ID of a Neutron external network.
|
||||||
|
type: str
|
||||||
|
delete_public_ip:
|
||||||
|
description:
|
||||||
|
- When C(state=absent) and this option is true, any public IP address
|
||||||
|
associated with the VIP will be deleted along with the load balancer.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
listeners:
|
||||||
|
description:
|
||||||
|
- A list of listeners that attached to the load balancer.
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The listener name or ID.
|
||||||
|
protocol:
|
||||||
|
description:
|
||||||
|
- The protocol for the listener.
|
||||||
|
default: HTTP
|
||||||
|
protocol_port:
|
||||||
|
description:
|
||||||
|
- The protocol port number for the listener.
|
||||||
|
default: 80
|
||||||
|
pool:
|
||||||
|
description:
|
||||||
|
- The pool attached to the listener.
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The pool name or ID.
|
||||||
|
protocol:
|
||||||
|
description:
|
||||||
|
- The protocol for the pool.
|
||||||
|
default: HTTP
|
||||||
|
lb_algorithm:
|
||||||
|
description:
|
||||||
|
- The load balancing algorithm for the pool.
|
||||||
|
default: ROUND_ROBIN
|
||||||
|
members:
|
||||||
|
description:
|
||||||
|
- A list of members that added to the pool.
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The member name or ID.
|
||||||
|
address:
|
||||||
|
description:
|
||||||
|
- The IP address of the member.
|
||||||
|
protocol_port:
|
||||||
|
description:
|
||||||
|
- The protocol port number for the member.
|
||||||
|
default: 80
|
||||||
|
subnet:
|
||||||
|
description:
|
||||||
|
- The name or ID of the subnet the member service is
|
||||||
|
accessible from.
|
||||||
|
elements: dict
|
||||||
|
type: list
|
||||||
|
wait:
|
||||||
|
description:
|
||||||
|
- If the module should wait for the load balancer to be created or
|
||||||
|
deleted.
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
timeout:
|
||||||
|
description:
|
||||||
|
- The amount of time the module should wait.
|
||||||
|
default: 180
|
||||||
|
type: int
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
id:
|
||||||
|
description: The load balancer UUID.
|
||||||
|
returned: On success when C(state=present)
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
loadbalancer:
|
||||||
|
description: Dictionary describing the load balancer.
|
||||||
|
returned: On success when C(state=present)
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
type: str
|
||||||
|
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
||||||
|
name:
|
||||||
|
description: Name given to the load balancer.
|
||||||
|
type: str
|
||||||
|
sample: "lingxian_test"
|
||||||
|
vip_network_id:
|
||||||
|
description: Network ID the load balancer virtual IP port belongs in.
|
||||||
|
type: str
|
||||||
|
sample: "f171db43-56fd-41cf-82d7-4e91d741762e"
|
||||||
|
vip_subnet_id:
|
||||||
|
description: Subnet ID the load balancer virtual IP port belongs in.
|
||||||
|
type: str
|
||||||
|
sample: "c53e3c70-9d62-409a-9f71-db148e7aa853"
|
||||||
|
vip_port_id:
|
||||||
|
description: The load balancer virtual IP port ID.
|
||||||
|
type: str
|
||||||
|
sample: "2061395c-1c01-47ab-b925-c91b93df9c1d"
|
||||||
|
vip_address:
|
||||||
|
description: The load balancer virtual IP address.
|
||||||
|
type: str
|
||||||
|
sample: "192.168.2.88"
|
||||||
|
public_vip_address:
|
||||||
|
description: The load balancer public VIP address.
|
||||||
|
type: str
|
||||||
|
sample: "10.17.8.254"
|
||||||
|
provisioning_status:
|
||||||
|
description: The provisioning status of the load balancer.
|
||||||
|
type: str
|
||||||
|
sample: "ACTIVE"
|
||||||
|
operating_status:
|
||||||
|
description: The operating status of the load balancer.
|
||||||
|
type: str
|
||||||
|
sample: "ONLINE"
|
||||||
|
is_admin_state_up:
|
||||||
|
description: The administrative state of the load balancer.
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
listeners:
|
||||||
|
description: The associated listener IDs, if any.
|
||||||
|
type: list
|
||||||
|
sample: [{"id": "7aa1b380-beec-459c-a8a7-3a4fb6d30645"}, {"id": "692d06b8-c4f8-4bdb-b2a3-5a263cc23ba6"}]
|
||||||
|
pools:
|
||||||
|
description: The associated pool IDs, if any.
|
||||||
|
type: list
|
||||||
|
sample: [{"id": "27b78d92-cee1-4646-b831-e3b90a7fa714"}, {"id": "befc1fb5-1992-4697-bdb9-eee330989344"}]
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create a load balancer by specifying the VIP subnet.
|
||||||
|
- openstack.cloud.loadbalancer:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: admin
|
||||||
|
password: passme
|
||||||
|
project_name: admin
|
||||||
|
state: present
|
||||||
|
name: my_lb
|
||||||
|
vip_subnet: my_subnet
|
||||||
|
timeout: 150
|
||||||
|
|
||||||
|
# Create a load balancer by specifying the VIP network and the IP address.
|
||||||
|
- openstack.cloud.loadbalancer:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: admin
|
||||||
|
password: passme
|
||||||
|
project_name: admin
|
||||||
|
state: present
|
||||||
|
name: my_lb
|
||||||
|
vip_network: my_network
|
||||||
|
vip_address: 192.168.0.11
|
||||||
|
|
||||||
|
# Create a load balancer together with its sub-resources in the 'all in one'
|
||||||
|
# way. A public IP address is also allocated to the load balancer VIP.
|
||||||
|
- openstack.cloud.loadbalancer:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: admin
|
||||||
|
password: passme
|
||||||
|
project_name: admin
|
||||||
|
name: lingxian_test
|
||||||
|
state: present
|
||||||
|
vip_subnet: kong_subnet
|
||||||
|
auto_public_ip: yes
|
||||||
|
public_network: public
|
||||||
|
listeners:
|
||||||
|
- name: lingxian_80
|
||||||
|
protocol: TCP
|
||||||
|
protocol_port: 80
|
||||||
|
pool:
|
||||||
|
name: lingxian_80_pool
|
||||||
|
protocol: TCP
|
||||||
|
members:
|
||||||
|
- name: mywebserver1
|
||||||
|
address: 192.168.2.81
|
||||||
|
protocol_port: 80
|
||||||
|
subnet: webserver_subnet
|
||||||
|
- name: lingxian_8080
|
||||||
|
protocol: TCP
|
||||||
|
protocol_port: 8080
|
||||||
|
pool:
|
||||||
|
name: lingxian_8080-pool
|
||||||
|
protocol: TCP
|
||||||
|
members:
|
||||||
|
- name: mywebserver2
|
||||||
|
address: 192.168.2.82
|
||||||
|
protocol_port: 8080
|
||||||
|
wait: yes
|
||||||
|
timeout: 600
|
||||||
|
|
||||||
|
# Delete a load balancer(and all its related resources)
|
||||||
|
- openstack.cloud.loadbalancer:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: admin
|
||||||
|
password: passme
|
||||||
|
project_name: admin
|
||||||
|
state: absent
|
||||||
|
name: my_lb
|
||||||
|
|
||||||
|
# Delete a load balancer(and all its related resources) together with the
|
||||||
|
# public IP address(if any) attached to it.
|
||||||
|
- openstack.cloud.loadbalancer:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: admin
|
||||||
|
password: passme
|
||||||
|
project_name: admin
|
||||||
|
state: absent
|
||||||
|
name: my_lb
|
||||||
|
delete_public_ip: yes
|
||||||
|
'''
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def _wait_for_lb(module, cloud, lb, status, failures, interval=5):
|
||||||
|
"""Wait for load balancer to be in a particular provisioning status."""
|
||||||
|
timeout = module.params['timeout']
|
||||||
|
|
||||||
|
total_sleep = 0
|
||||||
|
if failures is None:
|
||||||
|
failures = []
|
||||||
|
|
||||||
|
while total_sleep < timeout:
|
||||||
|
lb = cloud.load_balancer.find_load_balancer(lb.id)
|
||||||
|
|
||||||
|
if lb:
|
||||||
|
if lb.provisioning_status == status:
|
||||||
|
return None
|
||||||
|
if lb.provisioning_status in failures:
|
||||||
|
module.fail_json(
|
||||||
|
msg="Load Balancer %s transitioned to failure state %s" %
|
||||||
|
(lb.id, lb.provisioning_status)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if status == "DELETED":
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
module.fail_json(
|
||||||
|
msg="Load Balancer %s transitioned to DELETED" % lb.id
|
||||||
|
)
|
||||||
|
|
||||||
|
time.sleep(interval)
|
||||||
|
total_sleep += interval
|
||||||
|
|
||||||
|
module.fail_json(
|
||||||
|
msg="Timeout waiting for Load Balancer %s to transition to %s" %
|
||||||
|
(lb.id, status)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
vip_network=dict(required=False),
|
||||||
|
vip_subnet=dict(required=False),
|
||||||
|
vip_port=dict(required=False),
|
||||||
|
vip_address=dict(required=False),
|
||||||
|
listeners=dict(type='list', default=[], elements='dict'),
|
||||||
|
public_ip_address=dict(required=False, default=None),
|
||||||
|
auto_public_ip=dict(required=False, default=False, type='bool'),
|
||||||
|
public_network=dict(required=False),
|
||||||
|
delete_public_ip=dict(required=False, default=False, type='bool'),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
|
||||||
|
vip_network = module.params['vip_network']
|
||||||
|
vip_subnet = module.params['vip_subnet']
|
||||||
|
vip_port = module.params['vip_port']
|
||||||
|
listeners = module.params['listeners']
|
||||||
|
public_vip_address = module.params['public_ip_address']
|
||||||
|
allocate_fip = module.params['auto_public_ip']
|
||||||
|
delete_fip = module.params['delete_public_ip']
|
||||||
|
public_network = module.params['public_network']
|
||||||
|
|
||||||
|
vip_network_id = None
|
||||||
|
vip_subnet_id = None
|
||||||
|
vip_port_id = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
changed = False
|
||||||
|
lb = cloud.load_balancer.find_load_balancer(
|
||||||
|
name_or_id=module.params['name'])
|
||||||
|
|
||||||
|
if module.params['state'] == 'present':
|
||||||
|
if not lb:
|
||||||
|
if not (vip_network or vip_subnet or vip_port):
|
||||||
|
module.fail_json(
|
||||||
|
msg="One of vip_network, vip_subnet, or vip_port must "
|
||||||
|
"be specified for load balancer creation"
|
||||||
|
)
|
||||||
|
|
||||||
|
if vip_network:
|
||||||
|
network = cloud.get_network(vip_network)
|
||||||
|
if not network:
|
||||||
|
module.fail_json(
|
||||||
|
msg='network %s is not found' % vip_network
|
||||||
|
)
|
||||||
|
vip_network_id = network.id
|
||||||
|
if vip_subnet:
|
||||||
|
subnet = cloud.get_subnet(vip_subnet)
|
||||||
|
if not subnet:
|
||||||
|
module.fail_json(
|
||||||
|
msg='subnet %s is not found' % vip_subnet
|
||||||
|
)
|
||||||
|
vip_subnet_id = subnet.id
|
||||||
|
if vip_port:
|
||||||
|
port = cloud.get_port(vip_port)
|
||||||
|
if not port:
|
||||||
|
module.fail_json(
|
||||||
|
msg='port %s is not found' % vip_port
|
||||||
|
)
|
||||||
|
vip_port_id = port.id
|
||||||
|
|
||||||
|
lb = cloud.load_balancer.create_load_balancer(
|
||||||
|
name=module.params['name'],
|
||||||
|
vip_network_id=vip_network_id,
|
||||||
|
vip_subnet_id=vip_subnet_id,
|
||||||
|
vip_port_id=vip_port_id,
|
||||||
|
vip_address=module.params['vip_address'],
|
||||||
|
)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if not listeners and not module.params['wait']:
|
||||||
|
module.exit_json(
|
||||||
|
changed=changed,
|
||||||
|
loadbalancer=lb.to_dict(),
|
||||||
|
id=lb.id
|
||||||
|
)
|
||||||
|
|
||||||
|
_wait_for_lb(module, cloud, lb, "ACTIVE", ["ERROR"])
|
||||||
|
|
||||||
|
for listener_def in listeners:
|
||||||
|
listener_name = listener_def.get("name")
|
||||||
|
pool_def = listener_def.get("pool")
|
||||||
|
|
||||||
|
if not listener_name:
|
||||||
|
module.fail_json(msg='listener name is required')
|
||||||
|
|
||||||
|
listener = cloud.load_balancer.find_listener(
|
||||||
|
name_or_id=listener_name
|
||||||
|
)
|
||||||
|
|
||||||
|
if not listener:
|
||||||
|
_wait_for_lb(module, cloud, lb, "ACTIVE", ["ERROR"])
|
||||||
|
|
||||||
|
protocol = listener_def.get("protocol", "HTTP")
|
||||||
|
protocol_port = listener_def.get("protocol_port", 80)
|
||||||
|
|
||||||
|
listener = cloud.load_balancer.create_listener(
|
||||||
|
name=listener_name,
|
||||||
|
loadbalancer_id=lb.id,
|
||||||
|
protocol=protocol,
|
||||||
|
protocol_port=protocol_port,
|
||||||
|
)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
# Ensure pool in the listener.
|
||||||
|
if pool_def:
|
||||||
|
pool_name = pool_def.get("name")
|
||||||
|
members = pool_def.get('members', [])
|
||||||
|
|
||||||
|
if not pool_name:
|
||||||
|
module.fail_json(msg='pool name is required')
|
||||||
|
|
||||||
|
pool = cloud.load_balancer.find_pool(name_or_id=pool_name)
|
||||||
|
|
||||||
|
if not pool:
|
||||||
|
_wait_for_lb(module, cloud, lb, "ACTIVE", ["ERROR"])
|
||||||
|
|
||||||
|
protocol = pool_def.get("protocol", "HTTP")
|
||||||
|
lb_algorithm = pool_def.get("lb_algorithm",
|
||||||
|
"ROUND_ROBIN")
|
||||||
|
|
||||||
|
pool = cloud.load_balancer.create_pool(
|
||||||
|
name=pool_name,
|
||||||
|
listener_id=listener.id,
|
||||||
|
protocol=protocol,
|
||||||
|
lb_algorithm=lb_algorithm
|
||||||
|
)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
# Ensure members in the pool
|
||||||
|
for member_def in members:
|
||||||
|
member_name = member_def.get("name")
|
||||||
|
if not member_name:
|
||||||
|
module.fail_json(msg='member name is required')
|
||||||
|
|
||||||
|
member = cloud.load_balancer.find_member(member_name,
|
||||||
|
pool.id)
|
||||||
|
|
||||||
|
if not member:
|
||||||
|
_wait_for_lb(module, cloud, lb, "ACTIVE",
|
||||||
|
["ERROR"])
|
||||||
|
|
||||||
|
address = member_def.get("address")
|
||||||
|
if not address:
|
||||||
|
module.fail_json(
|
||||||
|
msg='member address for member %s is '
|
||||||
|
'required' % member_name
|
||||||
|
)
|
||||||
|
|
||||||
|
subnet_id = member_def.get("subnet")
|
||||||
|
if subnet_id:
|
||||||
|
subnet = cloud.get_subnet(subnet_id)
|
||||||
|
if not subnet:
|
||||||
|
module.fail_json(
|
||||||
|
msg='subnet %s for member %s is not '
|
||||||
|
'found' % (subnet_id, member_name)
|
||||||
|
)
|
||||||
|
subnet_id = subnet.id
|
||||||
|
|
||||||
|
protocol_port = member_def.get("protocol_port", 80)
|
||||||
|
|
||||||
|
member = cloud.load_balancer.create_member(
|
||||||
|
pool,
|
||||||
|
name=member_name,
|
||||||
|
address=address,
|
||||||
|
protocol_port=protocol_port,
|
||||||
|
subnet_id=subnet_id
|
||||||
|
)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
# Associate public ip to the load balancer VIP. If
|
||||||
|
# public_vip_address is provided, use that IP, otherwise, either
|
||||||
|
# find an available public ip or create a new one.
|
||||||
|
fip = None
|
||||||
|
orig_public_ip = None
|
||||||
|
new_public_ip = None
|
||||||
|
if public_vip_address or allocate_fip:
|
||||||
|
ips = cloud.network.ips(
|
||||||
|
port_id=lb.vip_port_id,
|
||||||
|
fixed_ip_address=lb.vip_address
|
||||||
|
)
|
||||||
|
ips = list(ips)
|
||||||
|
if ips:
|
||||||
|
orig_public_ip = ips[0]
|
||||||
|
new_public_ip = orig_public_ip.floating_ip_address
|
||||||
|
|
||||||
|
if public_vip_address and public_vip_address != orig_public_ip:
|
||||||
|
fip = cloud.network.find_ip(public_vip_address)
|
||||||
|
if not fip:
|
||||||
|
module.fail_json(
|
||||||
|
msg='Public IP %s is unavailable' % public_vip_address
|
||||||
|
)
|
||||||
|
|
||||||
|
# Release origin public ip first
|
||||||
|
cloud.network.update_ip(
|
||||||
|
orig_public_ip,
|
||||||
|
fixed_ip_address=None,
|
||||||
|
port_id=None
|
||||||
|
)
|
||||||
|
|
||||||
|
# Associate new public ip
|
||||||
|
cloud.network.update_ip(
|
||||||
|
fip,
|
||||||
|
fixed_ip_address=lb.vip_address,
|
||||||
|
port_id=lb.vip_port_id
|
||||||
|
)
|
||||||
|
|
||||||
|
new_public_ip = public_vip_address
|
||||||
|
changed = True
|
||||||
|
elif allocate_fip and not orig_public_ip:
|
||||||
|
fip = cloud.network.find_available_ip()
|
||||||
|
if not fip:
|
||||||
|
if not public_network:
|
||||||
|
module.fail_json(msg="Public network is not provided")
|
||||||
|
|
||||||
|
pub_net = cloud.network.find_network(public_network)
|
||||||
|
if not pub_net:
|
||||||
|
module.fail_json(
|
||||||
|
msg='Public network %s not found' %
|
||||||
|
public_network
|
||||||
|
)
|
||||||
|
fip = cloud.network.create_ip(
|
||||||
|
floating_network_id=pub_net.id
|
||||||
|
)
|
||||||
|
|
||||||
|
cloud.network.update_ip(
|
||||||
|
fip,
|
||||||
|
fixed_ip_address=lb.vip_address,
|
||||||
|
port_id=lb.vip_port_id
|
||||||
|
)
|
||||||
|
|
||||||
|
new_public_ip = fip.floating_ip_address
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
# Include public_vip_address in the result.
|
||||||
|
lb = cloud.load_balancer.find_load_balancer(name_or_id=lb.id)
|
||||||
|
lb_dict = lb.to_dict()
|
||||||
|
lb_dict.update({"public_vip_address": new_public_ip})
|
||||||
|
|
||||||
|
module.exit_json(
|
||||||
|
changed=changed,
|
||||||
|
loadbalancer=lb_dict,
|
||||||
|
id=lb.id
|
||||||
|
)
|
||||||
|
elif module.params['state'] == 'absent':
|
||||||
|
changed = False
|
||||||
|
public_vip_address = None
|
||||||
|
|
||||||
|
if lb:
|
||||||
|
if delete_fip:
|
||||||
|
ips = cloud.network.ips(
|
||||||
|
port_id=lb.vip_port_id,
|
||||||
|
fixed_ip_address=lb.vip_address
|
||||||
|
)
|
||||||
|
ips = list(ips)
|
||||||
|
if ips:
|
||||||
|
public_vip_address = ips[0]
|
||||||
|
|
||||||
|
# Deleting load balancer with `cascade=False` does not make
|
||||||
|
# sense because the deletion will always fail if there are
|
||||||
|
# sub-resources.
|
||||||
|
cloud.load_balancer.delete_load_balancer(lb, cascade=True)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
if module.params['wait']:
|
||||||
|
_wait_for_lb(module, cloud, lb, "DELETED", ["ERROR"])
|
||||||
|
|
||||||
|
if delete_fip and public_vip_address:
|
||||||
|
cloud.network.delete_ip(public_vip_address)
|
||||||
|
changed = True
|
||||||
|
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
263
plugins/modules/network.py
Normal file
263
plugins/modules/network.py
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
||||||
|
# Copyright (c) 2013, Benno Joy <benno@ansible.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: network
|
||||||
|
short_description: Creates/removes networks from OpenStack
|
||||||
|
author: "Monty Taylor (@emonty)"
|
||||||
|
description:
|
||||||
|
- Add or remove network from OpenStack.
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name to be assigned to the network.
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
shared:
|
||||||
|
description:
|
||||||
|
- Whether this network is shared or not.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
admin_state_up:
|
||||||
|
description:
|
||||||
|
- Whether the state should be marked as up or down.
|
||||||
|
type: bool
|
||||||
|
default: 'yes'
|
||||||
|
external:
|
||||||
|
description:
|
||||||
|
- Whether this network is externally accessible.
|
||||||
|
type: bool
|
||||||
|
default: 'no'
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Indicate desired state of the resource.
|
||||||
|
choices: ['present', 'absent']
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
provider_physical_network:
|
||||||
|
description:
|
||||||
|
- The physical network where this network object is implemented.
|
||||||
|
type: str
|
||||||
|
provider_network_type:
|
||||||
|
description:
|
||||||
|
- The type of physical network that maps to this network resource.
|
||||||
|
type: str
|
||||||
|
provider_segmentation_id:
|
||||||
|
description:
|
||||||
|
- An isolated segment on the physical network. The I(network_type)
|
||||||
|
attribute defines the segmentation model. For example, if the
|
||||||
|
I(network_type) value is vlan, this ID is a vlan identifier. If
|
||||||
|
the I(network_type) value is gre, this ID is a gre key.
|
||||||
|
type: int
|
||||||
|
project:
|
||||||
|
description:
|
||||||
|
- Project name or ID containing the network (name admin-only)
|
||||||
|
type: str
|
||||||
|
port_security_enabled:
|
||||||
|
description:
|
||||||
|
- Whether port security is enabled on the network or not.
|
||||||
|
Network will use OpenStack defaults if this option is
|
||||||
|
not utilised. Requires openstacksdk>=0.18.
|
||||||
|
type: bool
|
||||||
|
mtu:
|
||||||
|
description:
|
||||||
|
- The maximum transmission unit (MTU) value to address fragmentation.
|
||||||
|
Network will use OpenStack defaults if this option is
|
||||||
|
not provided. Requires openstacksdk>=0.18.
|
||||||
|
type: int
|
||||||
|
dns_domain:
|
||||||
|
description:
|
||||||
|
- The DNS domain value to set. Requires openstacksdk>=0.29.
|
||||||
|
Network will use Openstack defaults if this option is
|
||||||
|
not provided.
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Create an externally accessible network named 'ext_network'.
|
||||||
|
- openstack.cloud.network:
|
||||||
|
cloud: mycloud
|
||||||
|
state: present
|
||||||
|
name: ext_network
|
||||||
|
external: true
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
network:
|
||||||
|
description: Dictionary describing the network.
|
||||||
|
returned: On success when I(state) is 'present'.
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Network ID.
|
||||||
|
type: str
|
||||||
|
sample: "4bb4f9a5-3bd2-4562-bf6a-d17a6341bb56"
|
||||||
|
name:
|
||||||
|
description: Network name.
|
||||||
|
type: str
|
||||||
|
sample: "ext_network"
|
||||||
|
shared:
|
||||||
|
description: Indicates whether this network is shared across all tenants.
|
||||||
|
type: bool
|
||||||
|
sample: false
|
||||||
|
status:
|
||||||
|
description: Network status.
|
||||||
|
type: str
|
||||||
|
sample: "ACTIVE"
|
||||||
|
mtu:
|
||||||
|
description: The MTU of a network resource.
|
||||||
|
type: int
|
||||||
|
sample: 0
|
||||||
|
dns_domain:
|
||||||
|
description: The DNS domain of a network resource.
|
||||||
|
type: str
|
||||||
|
sample: "sample.openstack.org."
|
||||||
|
admin_state_up:
|
||||||
|
description: The administrative state of the network.
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
port_security_enabled:
|
||||||
|
description: The port security status
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
router:external:
|
||||||
|
description: Indicates whether this network is externally accessible.
|
||||||
|
type: bool
|
||||||
|
sample: true
|
||||||
|
tenant_id:
|
||||||
|
description: The tenant ID.
|
||||||
|
type: str
|
||||||
|
sample: "06820f94b9f54b119636be2728d216fc"
|
||||||
|
subnets:
|
||||||
|
description: The associated subnets.
|
||||||
|
type: list
|
||||||
|
sample: []
|
||||||
|
"provider:physical_network":
|
||||||
|
description: The physical network where this network object is implemented.
|
||||||
|
type: str
|
||||||
|
sample: my_vlan_net
|
||||||
|
"provider:network_type":
|
||||||
|
description: The type of physical network that maps to this network resource.
|
||||||
|
type: str
|
||||||
|
sample: vlan
|
||||||
|
"provider:segmentation_id":
|
||||||
|
description: An isolated segment on the physical network.
|
||||||
|
type: str
|
||||||
|
sample: 101
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=True),
|
||||||
|
shared=dict(default=False, type='bool'),
|
||||||
|
admin_state_up=dict(default=True, type='bool'),
|
||||||
|
external=dict(default=False, type='bool'),
|
||||||
|
provider_physical_network=dict(required=False),
|
||||||
|
provider_network_type=dict(required=False),
|
||||||
|
provider_segmentation_id=dict(required=False, type='int'),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
project=dict(default=None),
|
||||||
|
port_security_enabled=dict(type='bool'),
|
||||||
|
mtu=dict(required=False, type='int'),
|
||||||
|
dns_domain=dict(required=False)
|
||||||
|
)
|
||||||
|
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
state = module.params['state']
|
||||||
|
name = module.params['name']
|
||||||
|
shared = module.params['shared']
|
||||||
|
admin_state_up = module.params['admin_state_up']
|
||||||
|
external = module.params['external']
|
||||||
|
provider_physical_network = module.params['provider_physical_network']
|
||||||
|
provider_network_type = module.params['provider_network_type']
|
||||||
|
provider_segmentation_id = module.params['provider_segmentation_id']
|
||||||
|
project = module.params['project']
|
||||||
|
|
||||||
|
net_create_kwargs = {}
|
||||||
|
min_version = None
|
||||||
|
|
||||||
|
if module.params['mtu'] is not None:
|
||||||
|
min_version = '0.18.0'
|
||||||
|
net_create_kwargs['mtu_size'] = module.params['mtu']
|
||||||
|
|
||||||
|
if module.params['port_security_enabled'] is not None:
|
||||||
|
min_version = '0.18.0'
|
||||||
|
net_create_kwargs['port_security_enabled'] = module.params['port_security_enabled']
|
||||||
|
|
||||||
|
if module.params['dns_domain'] is not None:
|
||||||
|
min_version = '0.29.0'
|
||||||
|
net_create_kwargs['dns_domain'] = module.params['dns_domain']
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module, min_version)
|
||||||
|
try:
|
||||||
|
if project is not None:
|
||||||
|
proj = cloud.get_project(project)
|
||||||
|
if proj is None:
|
||||||
|
module.fail_json(msg='Project %s could not be found' % project)
|
||||||
|
project_id = proj['id']
|
||||||
|
filters = {'tenant_id': project_id}
|
||||||
|
else:
|
||||||
|
project_id = None
|
||||||
|
filters = None
|
||||||
|
net = cloud.get_network(name, filters=filters)
|
||||||
|
|
||||||
|
if state == 'present':
|
||||||
|
if not net:
|
||||||
|
provider = {}
|
||||||
|
if provider_physical_network:
|
||||||
|
provider['physical_network'] = provider_physical_network
|
||||||
|
if provider_network_type:
|
||||||
|
provider['network_type'] = provider_network_type
|
||||||
|
if provider_segmentation_id:
|
||||||
|
provider['segmentation_id'] = provider_segmentation_id
|
||||||
|
|
||||||
|
if project_id is not None:
|
||||||
|
net = cloud.create_network(name, shared, admin_state_up,
|
||||||
|
external, provider, project_id,
|
||||||
|
**net_create_kwargs)
|
||||||
|
else:
|
||||||
|
net = cloud.create_network(name, shared, admin_state_up,
|
||||||
|
external, provider,
|
||||||
|
**net_create_kwargs)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
changed = False
|
||||||
|
module.exit_json(changed=changed, network=net, id=net['id'])
|
||||||
|
|
||||||
|
elif state == 'absent':
|
||||||
|
if not net:
|
||||||
|
module.exit_json(changed=False)
|
||||||
|
else:
|
||||||
|
cloud.delete_network(name)
|
||||||
|
module.exit_json(changed=True)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
156
plugins/modules/networks_info.py
Normal file
156
plugins/modules/networks_info.py
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: networks_info
|
||||||
|
short_description: Retrieve information about one or more OpenStack networks.
|
||||||
|
author: "Davide Agnello (@dagnello)"
|
||||||
|
description:
|
||||||
|
- Retrieve information about one or more networks from OpenStack.
|
||||||
|
- This module was called C(openstack.cloud.networks_facts) before Ansible 2.9, returning C(ansible_facts).
|
||||||
|
Note that the M(openstack.cloud.networks_info) module no longer returns C(ansible_facts)!
|
||||||
|
options:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name or ID of the Network
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
filters:
|
||||||
|
description:
|
||||||
|
- A dictionary of meta data to use for further filtering. Elements of
|
||||||
|
this dictionary may be additional dictionaries.
|
||||||
|
required: false
|
||||||
|
type: dict
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: Gather information about previously created networks
|
||||||
|
openstack.cloud.networks_info:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: user
|
||||||
|
password: password
|
||||||
|
project_name: someproject
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Show openstack networks
|
||||||
|
debug:
|
||||||
|
msg: "{{ result.openstack_networks }}"
|
||||||
|
|
||||||
|
- name: Gather information about a previously created network by name
|
||||||
|
openstack.cloud.networks_info:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: user
|
||||||
|
password: password
|
||||||
|
project_name: someproject
|
||||||
|
name: network1
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Show openstack networks
|
||||||
|
debug:
|
||||||
|
msg: "{{ result.openstack_networks }}"
|
||||||
|
|
||||||
|
- name: Gather information about a previously created network with filter
|
||||||
|
# Note: name and filters parameters are Not mutually exclusive
|
||||||
|
openstack.cloud.networks_info:
|
||||||
|
auth:
|
||||||
|
auth_url: https://identity.example.com
|
||||||
|
username: user
|
||||||
|
password: password
|
||||||
|
project_name: someproject
|
||||||
|
filters:
|
||||||
|
tenant_id: 55e2ce24b2a245b09f181bf025724cbe
|
||||||
|
subnets:
|
||||||
|
- 057d4bdf-6d4d-4728-bb0f-5ac45a6f7400
|
||||||
|
- 443d4dc0-91d4-4998-b21c-357d10433483
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Show openstack networks
|
||||||
|
debug:
|
||||||
|
msg: "{{ result.openstack_networks }}"
|
||||||
|
'''
|
||||||
|
|
||||||
|
RETURN = '''
|
||||||
|
openstack_networks:
|
||||||
|
description: has all the openstack information about the networks
|
||||||
|
returned: always, but can be null
|
||||||
|
type: complex
|
||||||
|
contains:
|
||||||
|
id:
|
||||||
|
description: Unique UUID.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description: Name given to the network.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
status:
|
||||||
|
description: Network status.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
subnets:
|
||||||
|
description: Subnet(s) included in this network.
|
||||||
|
returned: success
|
||||||
|
type: list
|
||||||
|
elements: str
|
||||||
|
tenant_id:
|
||||||
|
description: Tenant id associated with this network.
|
||||||
|
returned: success
|
||||||
|
type: str
|
||||||
|
shared:
|
||||||
|
description: Network shared flag.
|
||||||
|
returned: success
|
||||||
|
type: bool
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (
|
||||||
|
openstack_full_argument_spec,
|
||||||
|
openstack_cloud_from_module,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=False, default=None),
|
||||||
|
filters=dict(required=False, type='dict', default=None)
|
||||||
|
)
|
||||||
|
module = AnsibleModule(argument_spec)
|
||||||
|
is_old_facts = module._name == 'openstack.cloud.networks_facts'
|
||||||
|
if is_old_facts:
|
||||||
|
module.deprecate("The 'openstack.cloud.networks_facts' module has been renamed to 'openstack.cloud.networks_info', "
|
||||||
|
"and the renamed one no longer returns ansible_facts", version='2.13')
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
networks = cloud.search_networks(module.params['name'],
|
||||||
|
module.params['filters'])
|
||||||
|
if is_old_facts:
|
||||||
|
module.exit_json(changed=False, ansible_facts=dict(
|
||||||
|
openstack_networks=networks))
|
||||||
|
else:
|
||||||
|
module.exit_json(changed=False, openstack_networks=networks)
|
||||||
|
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
129
plugins/modules/object.py
Normal file
129
plugins/modules/object.py
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
||||||
|
# Copyright (c) 2013, Benno Joy <benno@ansible.com>
|
||||||
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
|
|
||||||
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
|
'status': ['preview'],
|
||||||
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: object
|
||||||
|
short_description: Create or Delete objects and containers from OpenStack
|
||||||
|
author: "Monty Taylor (@emonty)"
|
||||||
|
description:
|
||||||
|
- Create or Delete objects and containers from OpenStack
|
||||||
|
options:
|
||||||
|
container:
|
||||||
|
description:
|
||||||
|
- The name of the container in which to create the object
|
||||||
|
required: true
|
||||||
|
type: str
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name to be give to the object. If omitted, operations will be on
|
||||||
|
the entire container
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
filename:
|
||||||
|
description:
|
||||||
|
- Path to local file to be uploaded.
|
||||||
|
required: false
|
||||||
|
type: str
|
||||||
|
container_access:
|
||||||
|
description:
|
||||||
|
- desired container access level.
|
||||||
|
required: false
|
||||||
|
choices: ['private', 'public']
|
||||||
|
default: private
|
||||||
|
type: str
|
||||||
|
state:
|
||||||
|
description:
|
||||||
|
- Should the resource be present or absent.
|
||||||
|
choices: [present, absent]
|
||||||
|
default: present
|
||||||
|
type: str
|
||||||
|
requirements:
|
||||||
|
- "python >= 3.6"
|
||||||
|
- "openstacksdk"
|
||||||
|
|
||||||
|
extends_documentation_fragment:
|
||||||
|
- openstack.cloud.openstack
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- name: "Create a object named 'fstab' in the 'config' container"
|
||||||
|
openstack.cloud.object:
|
||||||
|
cloud: mordred
|
||||||
|
state: present
|
||||||
|
name: fstab
|
||||||
|
container: config
|
||||||
|
filename: /etc/fstab
|
||||||
|
|
||||||
|
- name: Delete a container called config and all of its contents
|
||||||
|
openstack.cloud.object:
|
||||||
|
cloud: rax-iad
|
||||||
|
state: absent
|
||||||
|
container: config
|
||||||
|
'''
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
|
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
||||||
|
openstack_module_kwargs,
|
||||||
|
openstack_cloud_from_module)
|
||||||
|
|
||||||
|
|
||||||
|
def process_object(
|
||||||
|
cloud_obj, container, name, filename, container_access, **kwargs):
|
||||||
|
|
||||||
|
changed = False
|
||||||
|
container_obj = cloud_obj.get_container(container)
|
||||||
|
if kwargs['state'] == 'present':
|
||||||
|
if not container_obj:
|
||||||
|
container_obj = cloud_obj.create_container(container)
|
||||||
|
changed = True
|
||||||
|
if cloud_obj.get_container_access(container) != container_access:
|
||||||
|
cloud_obj.set_container_access(container, container_access)
|
||||||
|
changed = True
|
||||||
|
if name:
|
||||||
|
if cloud_obj.is_object_stale(container, name, filename):
|
||||||
|
cloud_obj.create_object(container, name, filename)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
if container_obj:
|
||||||
|
if name:
|
||||||
|
if cloud_obj.get_object_metadata(container, name):
|
||||||
|
cloud_obj.delete_object(container, name)
|
||||||
|
changed = True
|
||||||
|
else:
|
||||||
|
cloud_obj.delete_container(container)
|
||||||
|
changed = True
|
||||||
|
return changed
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
argument_spec = openstack_full_argument_spec(
|
||||||
|
name=dict(required=False, default=None),
|
||||||
|
container=dict(required=True),
|
||||||
|
filename=dict(required=False, default=None),
|
||||||
|
container_access=dict(default='private', choices=['private', 'public']),
|
||||||
|
state=dict(default='present', choices=['absent', 'present']),
|
||||||
|
)
|
||||||
|
module_kwargs = openstack_module_kwargs()
|
||||||
|
module = AnsibleModule(argument_spec, **module_kwargs)
|
||||||
|
|
||||||
|
sdk, cloud = openstack_cloud_from_module(module)
|
||||||
|
try:
|
||||||
|
changed = process_object(cloud, **module.params)
|
||||||
|
|
||||||
|
module.exit_json(changed=changed)
|
||||||
|
except sdk.exceptions.OpenStackCloudException as e:
|
||||||
|
module.fail_json(msg=str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -1,73 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_auth
|
|
||||||
short_description: Retrieve an auth token
|
|
||||||
author: "Monty Taylor (@emonty)"
|
|
||||||
description:
|
|
||||||
- Retrieve an auth token from an OpenStack Cloud
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
- name: Authenticate to the cloud and retrieve the service catalog
|
|
||||||
os_auth:
|
|
||||||
cloud: rax-dfw
|
|
||||||
|
|
||||||
- name: Show service catalog
|
|
||||||
debug:
|
|
||||||
var: service_catalog
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
auth_token:
|
|
||||||
description: Openstack API Auth Token
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
service_catalog:
|
|
||||||
description: A dictionary of available API endpoints
|
|
||||||
returned: success
|
|
||||||
type: dict
|
|
||||||
'''
|
|
||||||
|
|
||||||
import traceback
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
argument_spec = openstack_full_argument_spec()
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
module.exit_json(
|
|
||||||
changed=False,
|
|
||||||
ansible_facts=dict(
|
|
||||||
auth_token=cloud.auth_token,
|
|
||||||
service_catalog=cloud.service_catalog))
|
|
||||||
except Exception as e:
|
|
||||||
module.fail_json(msg=str(e), exception=traceback.format_exc())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_auth.py
Symbolic link
1
plugins/modules/os_auth.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
auth.py
|
@ -1,82 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_client_config
|
|
||||||
short_description: Get OpenStack Client config
|
|
||||||
description:
|
|
||||||
- Get I(openstack) client config data from clouds.yaml or environment
|
|
||||||
notes:
|
|
||||||
- Facts are placed in the C(openstack.clouds) variable.
|
|
||||||
options:
|
|
||||||
clouds:
|
|
||||||
description:
|
|
||||||
- List of clouds to limit the return list to. No value means return
|
|
||||||
information on all configured clouds
|
|
||||||
required: false
|
|
||||||
default: []
|
|
||||||
type: list
|
|
||||||
elements: str
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
author: "Monty Taylor (@emonty)"
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
- name: Get list of clouds that do not support security groups
|
|
||||||
os_client_config:
|
|
||||||
|
|
||||||
- debug:
|
|
||||||
var: "{{ item }}"
|
|
||||||
with_items: "{{ openstack.clouds | rejectattr('secgroup_source', 'none') | list }}"
|
|
||||||
|
|
||||||
- name: Get the information back just about the mordred cloud
|
|
||||||
os_client_config:
|
|
||||||
clouds:
|
|
||||||
- mordred
|
|
||||||
'''
|
|
||||||
|
|
||||||
try:
|
|
||||||
import openstack.config
|
|
||||||
from openstack import exceptions
|
|
||||||
HAS_OPENSTACKSDK = True
|
|
||||||
except ImportError:
|
|
||||||
HAS_OPENSTACKSDK = False
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
module = AnsibleModule(argument_spec=dict(
|
|
||||||
clouds=dict(required=False, type='list', default=[], elements='str'),
|
|
||||||
))
|
|
||||||
|
|
||||||
if not HAS_OPENSTACKSDK:
|
|
||||||
module.fail_json(msg='openstacksdk is required for this module')
|
|
||||||
|
|
||||||
p = module.params
|
|
||||||
|
|
||||||
try:
|
|
||||||
config = openstack.config.OpenStackConfig()
|
|
||||||
clouds = []
|
|
||||||
for cloud in config.get_all_clouds():
|
|
||||||
if not p['clouds'] or cloud.name in p['clouds']:
|
|
||||||
cloud.config['name'] = cloud.name
|
|
||||||
clouds.append(cloud.config)
|
|
||||||
module.exit_json(ansible_facts=dict(openstack=dict(clouds=clouds)))
|
|
||||||
except exceptions.ConfigException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
1
plugins/modules/os_client_config.py
Symbolic link
1
plugins/modules/os_client_config.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
config.py
|
@ -1,299 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2018 Catalyst IT Ltd.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_coe_cluster
|
|
||||||
short_description: Add/Remove COE cluster from OpenStack Cloud
|
|
||||||
author: "Feilong Wang (@flwang)"
|
|
||||||
description:
|
|
||||||
- Add or Remove COE cluster from the OpenStack Container Infra service.
|
|
||||||
options:
|
|
||||||
cluster_template_id:
|
|
||||||
description:
|
|
||||||
- The template ID of cluster template.
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
discovery_url:
|
|
||||||
description:
|
|
||||||
- Url used for cluster node discovery
|
|
||||||
type: str
|
|
||||||
docker_volume_size:
|
|
||||||
description:
|
|
||||||
- The size in GB of the docker volume
|
|
||||||
type: int
|
|
||||||
flavor_id:
|
|
||||||
description:
|
|
||||||
- The flavor of the minion node for this ClusterTemplate
|
|
||||||
type: str
|
|
||||||
keypair:
|
|
||||||
description:
|
|
||||||
- Name of the keypair to use.
|
|
||||||
type: str
|
|
||||||
labels:
|
|
||||||
description:
|
|
||||||
- One or more key/value pairs
|
|
||||||
type: raw
|
|
||||||
master_flavor_id:
|
|
||||||
description:
|
|
||||||
- The flavor of the master node for this ClusterTemplate
|
|
||||||
type: str
|
|
||||||
master_count:
|
|
||||||
description:
|
|
||||||
- The number of master nodes for this cluster
|
|
||||||
default: 1
|
|
||||||
type: int
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name that has to be given to the cluster template
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
node_count:
|
|
||||||
description:
|
|
||||||
- The number of nodes for this cluster
|
|
||||||
default: 1
|
|
||||||
type: int
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Indicate desired state of the resource.
|
|
||||||
choices: [present, absent]
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
timeout:
|
|
||||||
description:
|
|
||||||
- Timeout for creating the cluster in minutes. Default to 60 mins
|
|
||||||
if not set
|
|
||||||
default: 60
|
|
||||||
type: int
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
id:
|
|
||||||
description: The cluster UUID.
|
|
||||||
returned: On success when I(state) is 'present'
|
|
||||||
type: str
|
|
||||||
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
|
||||||
cluster:
|
|
||||||
description: Dictionary describing the cluster.
|
|
||||||
returned: On success when I(state) is 'present'
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
api_address:
|
|
||||||
description:
|
|
||||||
- Api address of cluster master node
|
|
||||||
type: str
|
|
||||||
sample: https://172.24.4.30:6443
|
|
||||||
cluster_template_id:
|
|
||||||
description: The cluster_template UUID
|
|
||||||
type: str
|
|
||||||
sample: '7b1418c8-cea8-48fc-995d-52b66af9a9aa'
|
|
||||||
coe_version:
|
|
||||||
description:
|
|
||||||
- Version of the COE software currently running in this cluster
|
|
||||||
type: str
|
|
||||||
sample: v1.11.1
|
|
||||||
container_version:
|
|
||||||
description:
|
|
||||||
- "Version of the container software. Example: docker version."
|
|
||||||
type: str
|
|
||||||
sample: 1.12.6
|
|
||||||
created_at:
|
|
||||||
description:
|
|
||||||
- The time in UTC at which the cluster is created
|
|
||||||
type: str
|
|
||||||
sample: "2018-08-16T10:29:45+00:00"
|
|
||||||
create_timeout:
|
|
||||||
description:
|
|
||||||
- Timeout for creating the cluster in minutes. Default to 60 if
|
|
||||||
not set.
|
|
||||||
type: int
|
|
||||||
sample: 60
|
|
||||||
discovery_url:
|
|
||||||
description:
|
|
||||||
- Url used for cluster node discovery
|
|
||||||
type: str
|
|
||||||
sample: https://discovery.etcd.io/a42ee38e7113f31f4d6324f24367aae5
|
|
||||||
faults:
|
|
||||||
description:
|
|
||||||
- Fault info collected from the Heat resources of this cluster
|
|
||||||
type: dict
|
|
||||||
sample: {'0': 'ResourceInError: resources[0].resources...'}
|
|
||||||
flavor_id:
|
|
||||||
description:
|
|
||||||
- The flavor of the minion node for this cluster
|
|
||||||
type: str
|
|
||||||
sample: c1.c1r1
|
|
||||||
keypair:
|
|
||||||
description:
|
|
||||||
- Name of the keypair to use.
|
|
||||||
type: str
|
|
||||||
sample: mykey
|
|
||||||
labels:
|
|
||||||
description: One or more key/value pairs
|
|
||||||
type: dict
|
|
||||||
sample: {'key1': 'value1', 'key2': 'value2'}
|
|
||||||
master_addresses:
|
|
||||||
description:
|
|
||||||
- IP addresses of cluster master nodes
|
|
||||||
type: list
|
|
||||||
sample: ['172.24.4.5']
|
|
||||||
master_count:
|
|
||||||
description:
|
|
||||||
- The number of master nodes for this cluster.
|
|
||||||
type: int
|
|
||||||
sample: 1
|
|
||||||
master_flavor_id:
|
|
||||||
description:
|
|
||||||
- The flavor of the master node for this cluster
|
|
||||||
type: str
|
|
||||||
sample: c1.c1r1
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name that has to be given to the cluster
|
|
||||||
type: str
|
|
||||||
sample: k8scluster
|
|
||||||
node_addresses:
|
|
||||||
description:
|
|
||||||
- IP addresses of cluster slave nodes
|
|
||||||
type: list
|
|
||||||
sample: ['172.24.4.8']
|
|
||||||
node_count:
|
|
||||||
description:
|
|
||||||
- The number of master nodes for this cluster.
|
|
||||||
type: int
|
|
||||||
sample: 1
|
|
||||||
stack_id:
|
|
||||||
description:
|
|
||||||
- Stack id of the Heat stack
|
|
||||||
type: str
|
|
||||||
sample: '07767ec6-85f5-44cb-bd63-242a8e7f0d9d'
|
|
||||||
status:
|
|
||||||
description: Status of the cluster from the heat stack
|
|
||||||
type: str
|
|
||||||
sample: 'CREATE_COMLETE'
|
|
||||||
status_reason:
|
|
||||||
description:
|
|
||||||
- Status reason of the cluster from the heat stack
|
|
||||||
type: str
|
|
||||||
sample: 'Stack CREATE completed successfully'
|
|
||||||
updated_at:
|
|
||||||
description:
|
|
||||||
- The time in UTC at which the cluster is updated
|
|
||||||
type: str
|
|
||||||
sample: '2018-08-16T10:39:25+00:00'
|
|
||||||
id:
|
|
||||||
description:
|
|
||||||
- Unique UUID for this cluster
|
|
||||||
type: str
|
|
||||||
sample: '86246a4d-a16c-4a58-9e96ad7719fe0f9d'
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Create a new Kubernetes cluster
|
|
||||||
- os_coe_cluster:
|
|
||||||
name: k8s
|
|
||||||
cluster_template_id: k8s-ha
|
|
||||||
keypair: mykey
|
|
||||||
master_count: 3
|
|
||||||
node_count: 5
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_labels(labels):
|
|
||||||
if isinstance(labels, str):
|
|
||||||
labels_dict = {}
|
|
||||||
for kv_str in labels.split(","):
|
|
||||||
k, v = kv_str.split("=")
|
|
||||||
labels_dict[k] = v
|
|
||||||
return labels_dict
|
|
||||||
if not labels:
|
|
||||||
return {}
|
|
||||||
return labels
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
cluster_template_id=dict(required=True),
|
|
||||||
discovery_url=dict(default=None),
|
|
||||||
docker_volume_size=dict(type='int'),
|
|
||||||
flavor_id=dict(default=None),
|
|
||||||
keypair=dict(default=None),
|
|
||||||
labels=dict(default=None, type='raw'),
|
|
||||||
master_count=dict(type='int', default=1),
|
|
||||||
master_flavor_id=dict(default=None),
|
|
||||||
name=dict(required=True),
|
|
||||||
node_count=dict(type='int', default=1),
|
|
||||||
state=dict(default='present', choices=['absent', 'present']),
|
|
||||||
timeout=dict(type='int', default=60),
|
|
||||||
)
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
|
|
||||||
params = module.params.copy()
|
|
||||||
|
|
||||||
state = module.params['state']
|
|
||||||
name = module.params['name']
|
|
||||||
cluster_template_id = module.params['cluster_template_id']
|
|
||||||
|
|
||||||
kwargs = dict(
|
|
||||||
discovery_url=module.params['discovery_url'],
|
|
||||||
docker_volume_size=module.params['docker_volume_size'],
|
|
||||||
flavor_id=module.params['flavor_id'],
|
|
||||||
keypair=module.params['keypair'],
|
|
||||||
labels=_parse_labels(params['labels']),
|
|
||||||
master_count=module.params['master_count'],
|
|
||||||
master_flavor_id=module.params['master_flavor_id'],
|
|
||||||
node_count=module.params['node_count'],
|
|
||||||
create_timeout=module.params['timeout'],
|
|
||||||
)
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
changed = False
|
|
||||||
cluster = cloud.get_coe_cluster(name_or_id=name, filters={'cluster_template_id': cluster_template_id})
|
|
||||||
|
|
||||||
if state == 'present':
|
|
||||||
if not cluster:
|
|
||||||
cluster = cloud.create_coe_cluster(name, cluster_template_id=cluster_template_id, **kwargs)
|
|
||||||
changed = True
|
|
||||||
else:
|
|
||||||
changed = False
|
|
||||||
|
|
||||||
# NOTE (brtknr): At present, create_coe_cluster request returns
|
|
||||||
# cluster_id as `uuid` whereas get_coe_cluster request returns the
|
|
||||||
# same field as `id`. This behaviour may change in the future
|
|
||||||
# therefore try `id` first then `uuid`.
|
|
||||||
cluster_id = cluster.get('id', cluster.get('uuid'))
|
|
||||||
cluster['id'] = cluster['uuid'] = cluster_id
|
|
||||||
module.exit_json(changed=changed, cluster=cluster, id=cluster_id)
|
|
||||||
elif state == 'absent':
|
|
||||||
if not cluster:
|
|
||||||
module.exit_json(changed=False)
|
|
||||||
else:
|
|
||||||
cloud.delete_coe_cluster(name)
|
|
||||||
module.exit_json(changed=True)
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
1
plugins/modules/os_coe_cluster.py
Symbolic link
1
plugins/modules/os_coe_cluster.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
coe_cluster.py
|
@ -1,394 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2018 Catalyst IT Ltd.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_coe_cluster_template
|
|
||||||
short_description: Add/Remove COE cluster template from OpenStack Cloud
|
|
||||||
author: "Feilong Wang (@flwang)"
|
|
||||||
description:
|
|
||||||
- Add or Remove COE cluster template from the OpenStack Container Infra
|
|
||||||
service.
|
|
||||||
options:
|
|
||||||
coe:
|
|
||||||
description:
|
|
||||||
- The Container Orchestration Engine for this clustertemplate
|
|
||||||
choices: [kubernetes, swarm, mesos]
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
dns_nameserver:
|
|
||||||
description:
|
|
||||||
- The DNS nameserver address
|
|
||||||
default: '8.8.8.8'
|
|
||||||
type: str
|
|
||||||
docker_storage_driver:
|
|
||||||
description:
|
|
||||||
- Docker storage driver
|
|
||||||
choices: [devicemapper, overlay, overlay2]
|
|
||||||
type: str
|
|
||||||
docker_volume_size:
|
|
||||||
description:
|
|
||||||
- The size in GB of the docker volume
|
|
||||||
type: int
|
|
||||||
external_network_id:
|
|
||||||
description:
|
|
||||||
- The external network to attach to the Cluster
|
|
||||||
type: str
|
|
||||||
fixed_network:
|
|
||||||
description:
|
|
||||||
- The fixed network name to attach to the Cluster
|
|
||||||
type: str
|
|
||||||
fixed_subnet:
|
|
||||||
description:
|
|
||||||
- The fixed subnet name to attach to the Cluster
|
|
||||||
type: str
|
|
||||||
flavor_id:
|
|
||||||
description:
|
|
||||||
- The flavor of the minion node for this ClusterTemplate
|
|
||||||
type: str
|
|
||||||
floating_ip_enabled:
|
|
||||||
description:
|
|
||||||
- Indicates whether created clusters should have a floating ip or not
|
|
||||||
type: bool
|
|
||||||
default: true
|
|
||||||
keypair_id:
|
|
||||||
description:
|
|
||||||
- Name or ID of the keypair to use.
|
|
||||||
type: str
|
|
||||||
image_id:
|
|
||||||
description:
|
|
||||||
- Image id the cluster will be based on
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
labels:
|
|
||||||
description:
|
|
||||||
- One or more key/value pairs
|
|
||||||
type: raw
|
|
||||||
http_proxy:
|
|
||||||
description:
|
|
||||||
- Address of a proxy that will receive all HTTP requests and relay them
|
|
||||||
The format is a URL including a port number
|
|
||||||
type: str
|
|
||||||
https_proxy:
|
|
||||||
description:
|
|
||||||
- Address of a proxy that will receive all HTTPS requests and relay
|
|
||||||
them. The format is a URL including a port number
|
|
||||||
type: str
|
|
||||||
master_flavor_id:
|
|
||||||
description:
|
|
||||||
- The flavor of the master node for this ClusterTemplate
|
|
||||||
type: str
|
|
||||||
master_lb_enabled:
|
|
||||||
description:
|
|
||||||
- Indicates whether created clusters should have a load balancer
|
|
||||||
for master nodes or not
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name that has to be given to the cluster template
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
network_driver:
|
|
||||||
description:
|
|
||||||
- The name of the driver used for instantiating container networks
|
|
||||||
choices: [flannel, calico, docker]
|
|
||||||
type: str
|
|
||||||
no_proxy:
|
|
||||||
description:
|
|
||||||
- A comma separated list of IPs for which proxies should not be
|
|
||||||
used in the cluster
|
|
||||||
type: str
|
|
||||||
public:
|
|
||||||
description:
|
|
||||||
- Indicates whether the ClusterTemplate is public or not
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
registry_enabled:
|
|
||||||
description:
|
|
||||||
- Indicates whether the docker registry is enabled
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
server_type:
|
|
||||||
description:
|
|
||||||
- Server type for this ClusterTemplate
|
|
||||||
choices: [vm, bm]
|
|
||||||
default: vm
|
|
||||||
type: str
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Indicate desired state of the resource.
|
|
||||||
choices: [present, absent]
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
tls_disabled:
|
|
||||||
description:
|
|
||||||
- Indicates whether the TLS should be disabled
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
volume_driver:
|
|
||||||
description:
|
|
||||||
- The name of the driver used for instantiating container volumes
|
|
||||||
choices: [cinder, rexray]
|
|
||||||
type: str
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
id:
|
|
||||||
description: The cluster UUID.
|
|
||||||
returned: On success when I(state) is 'present'
|
|
||||||
type: str
|
|
||||||
sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69"
|
|
||||||
cluster_template:
|
|
||||||
description: Dictionary describing the template.
|
|
||||||
returned: On success when I(state) is 'present'
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
coe:
|
|
||||||
description: The Container Orchestration Engine for this clustertemplate
|
|
||||||
type: str
|
|
||||||
sample: kubernetes
|
|
||||||
dns_nameserver:
|
|
||||||
description: The DNS nameserver address
|
|
||||||
type: str
|
|
||||||
sample: '8.8.8.8'
|
|
||||||
docker_storage_driver:
|
|
||||||
description: Docker storage driver
|
|
||||||
type: str
|
|
||||||
sample: devicemapper
|
|
||||||
docker_volume_size:
|
|
||||||
description: The size in GB of the docker volume
|
|
||||||
type: int
|
|
||||||
sample: 5
|
|
||||||
external_network_id:
|
|
||||||
description: The external network to attach to the Cluster
|
|
||||||
type: str
|
|
||||||
sample: public
|
|
||||||
fixed_network:
|
|
||||||
description: The fixed network name to attach to the Cluster
|
|
||||||
type: str
|
|
||||||
sample: 07767ec6-85f5-44cb-bd63-242a8e7f0d9d
|
|
||||||
fixed_subnet:
|
|
||||||
description:
|
|
||||||
- The fixed subnet name to attach to the Cluster
|
|
||||||
type: str
|
|
||||||
sample: 05567ec6-85f5-44cb-bd63-242a8e7f0d9d
|
|
||||||
flavor_id:
|
|
||||||
description:
|
|
||||||
- The flavor of the minion node for this ClusterTemplate
|
|
||||||
type: str
|
|
||||||
sample: c1.c1r1
|
|
||||||
floating_ip_enabled:
|
|
||||||
description:
|
|
||||||
- Indicates whether created clusters should have a floating ip or not
|
|
||||||
type: bool
|
|
||||||
sample: true
|
|
||||||
keypair_id:
|
|
||||||
description:
|
|
||||||
- Name or ID of the keypair to use.
|
|
||||||
type: str
|
|
||||||
sample: mykey
|
|
||||||
image_id:
|
|
||||||
description:
|
|
||||||
- Image id the cluster will be based on
|
|
||||||
type: str
|
|
||||||
sample: 05567ec6-85f5-44cb-bd63-242a8e7f0e9d
|
|
||||||
labels:
|
|
||||||
description: One or more key/value pairs
|
|
||||||
type: dict
|
|
||||||
sample: {'key1': 'value1', 'key2': 'value2'}
|
|
||||||
http_proxy:
|
|
||||||
description:
|
|
||||||
- Address of a proxy that will receive all HTTP requests and relay them
|
|
||||||
The format is a URL including a port number
|
|
||||||
type: str
|
|
||||||
sample: http://10.0.0.11:9090
|
|
||||||
https_proxy:
|
|
||||||
description:
|
|
||||||
- Address of a proxy that will receive all HTTPS requests and relay
|
|
||||||
them. The format is a URL including a port number
|
|
||||||
type: str
|
|
||||||
sample: https://10.0.0.10:8443
|
|
||||||
master_flavor_id:
|
|
||||||
description:
|
|
||||||
- The flavor of the master node for this ClusterTemplate
|
|
||||||
type: str
|
|
||||||
sample: c1.c1r1
|
|
||||||
master_lb_enabled:
|
|
||||||
description:
|
|
||||||
- Indicates whether created clusters should have a load balancer
|
|
||||||
for master nodes or not
|
|
||||||
type: bool
|
|
||||||
sample: true
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name that has to be given to the cluster template
|
|
||||||
type: str
|
|
||||||
sample: k8scluster
|
|
||||||
network_driver:
|
|
||||||
description:
|
|
||||||
- The name of the driver used for instantiating container networks
|
|
||||||
type: str
|
|
||||||
sample: calico
|
|
||||||
no_proxy:
|
|
||||||
description:
|
|
||||||
- A comma separated list of IPs for which proxies should not be
|
|
||||||
used in the cluster
|
|
||||||
type: str
|
|
||||||
sample: 10.0.0.4,10.0.0.5
|
|
||||||
public:
|
|
||||||
description:
|
|
||||||
- Indicates whether the ClusterTemplate is public or not
|
|
||||||
type: bool
|
|
||||||
sample: false
|
|
||||||
registry_enabled:
|
|
||||||
description:
|
|
||||||
- Indicates whether the docker registry is enabled
|
|
||||||
type: bool
|
|
||||||
sample: false
|
|
||||||
server_type:
|
|
||||||
description:
|
|
||||||
- Server type for this ClusterTemplate
|
|
||||||
type: str
|
|
||||||
sample: vm
|
|
||||||
tls_disabled:
|
|
||||||
description:
|
|
||||||
- Indicates whether the TLS should be disabled
|
|
||||||
type: bool
|
|
||||||
sample: false
|
|
||||||
volume_driver:
|
|
||||||
description:
|
|
||||||
- The name of the driver used for instantiating container volumes
|
|
||||||
type: str
|
|
||||||
sample: cinder
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Create a new Kubernetes cluster template
|
|
||||||
- os_coe_cluster_template:
|
|
||||||
name: k8s
|
|
||||||
coe: kubernetes
|
|
||||||
keypair_id: mykey
|
|
||||||
image_id: 2a8c9888-9054-4b06-a1ca-2bb61f9adb72
|
|
||||||
public: no
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_labels(labels):
|
|
||||||
if isinstance(labels, str):
|
|
||||||
labels_dict = {}
|
|
||||||
for kv_str in labels.split(","):
|
|
||||||
k, v = kv_str.split("=")
|
|
||||||
labels_dict[k] = v
|
|
||||||
return labels_dict
|
|
||||||
if not labels:
|
|
||||||
return {}
|
|
||||||
return labels
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
coe=dict(required=True, choices=['kubernetes', 'swarm', 'mesos']),
|
|
||||||
dns_nameserver=dict(default='8.8.8.8'),
|
|
||||||
docker_storage_driver=dict(choices=['devicemapper', 'overlay', 'overlay2']),
|
|
||||||
docker_volume_size=dict(type='int'),
|
|
||||||
external_network_id=dict(default=None),
|
|
||||||
fixed_network=dict(default=None),
|
|
||||||
fixed_subnet=dict(default=None),
|
|
||||||
flavor_id=dict(default=None),
|
|
||||||
floating_ip_enabled=dict(type='bool', default=True),
|
|
||||||
keypair_id=dict(default=None),
|
|
||||||
image_id=dict(required=True),
|
|
||||||
labels=dict(default=None, type='raw'),
|
|
||||||
http_proxy=dict(default=None),
|
|
||||||
https_proxy=dict(default=None),
|
|
||||||
master_lb_enabled=dict(type='bool', default=False),
|
|
||||||
master_flavor_id=dict(default=None),
|
|
||||||
name=dict(required=True),
|
|
||||||
network_driver=dict(choices=['flannel', 'calico', 'docker']),
|
|
||||||
no_proxy=dict(default=None),
|
|
||||||
public=dict(type='bool', default=False),
|
|
||||||
registry_enabled=dict(type='bool', default=False),
|
|
||||||
server_type=dict(default="vm", choices=['vm', 'bm']),
|
|
||||||
state=dict(default='present', choices=['absent', 'present']),
|
|
||||||
tls_disabled=dict(type='bool', default=False),
|
|
||||||
volume_driver=dict(choices=['cinder', 'rexray']),
|
|
||||||
)
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
|
|
||||||
params = module.params.copy()
|
|
||||||
|
|
||||||
state = module.params['state']
|
|
||||||
name = module.params['name']
|
|
||||||
coe = module.params['coe']
|
|
||||||
image_id = module.params['image_id']
|
|
||||||
|
|
||||||
kwargs = dict(
|
|
||||||
dns_nameserver=module.params['dns_nameserver'],
|
|
||||||
docker_storage_driver=module.params['docker_storage_driver'],
|
|
||||||
docker_volume_size=module.params['docker_volume_size'],
|
|
||||||
external_network_id=module.params['external_network_id'],
|
|
||||||
fixed_network=module.params['fixed_network'],
|
|
||||||
fixed_subnet=module.params['fixed_subnet'],
|
|
||||||
flavor_id=module.params['flavor_id'],
|
|
||||||
floating_ip_enabled=module.params['floating_ip_enabled'],
|
|
||||||
keypair_id=module.params['keypair_id'],
|
|
||||||
labels=_parse_labels(params['labels']),
|
|
||||||
http_proxy=module.params['http_proxy'],
|
|
||||||
https_proxy=module.params['https_proxy'],
|
|
||||||
master_lb_enabled=module.params['master_lb_enabled'],
|
|
||||||
master_flavor_id=module.params['master_flavor_id'],
|
|
||||||
network_driver=module.params['network_driver'],
|
|
||||||
no_proxy=module.params['no_proxy'],
|
|
||||||
public=module.params['public'],
|
|
||||||
registry_enabled=module.params['registry_enabled'],
|
|
||||||
server_type=module.params['server_type'],
|
|
||||||
tls_disabled=module.params['tls_disabled'],
|
|
||||||
volume_driver=module.params['volume_driver'],
|
|
||||||
)
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
changed = False
|
|
||||||
template = cloud.get_coe_cluster_template(name_or_id=name, filters={'coe': coe, 'image_id': image_id})
|
|
||||||
|
|
||||||
if state == 'present':
|
|
||||||
if not template:
|
|
||||||
template = cloud.create_coe_cluster_template(name, coe=coe, image_id=image_id, **kwargs)
|
|
||||||
changed = True
|
|
||||||
else:
|
|
||||||
changed = False
|
|
||||||
|
|
||||||
module.exit_json(changed=changed, cluster_template=template, id=template['uuid'])
|
|
||||||
elif state == 'absent':
|
|
||||||
if not template:
|
|
||||||
module.exit_json(changed=False)
|
|
||||||
else:
|
|
||||||
cloud.delete_coe_cluster_template(name)
|
|
||||||
module.exit_json(changed=True)
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
1
plugins/modules/os_coe_cluster_template.py
Symbolic link
1
plugins/modules/os_coe_cluster_template.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
coe_cluster_template.py
|
@ -1,233 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2015 IBM
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_flavor_info
|
|
||||||
short_description: Retrieve information about one or more flavors
|
|
||||||
author: "David Shrewsbury (@Shrews)"
|
|
||||||
description:
|
|
||||||
- Retrieve information about available OpenStack instance flavors. By default,
|
|
||||||
information about ALL flavors are retrieved. Filters can be applied to get
|
|
||||||
information for only matching flavors. For example, you can filter on the
|
|
||||||
amount of RAM available to the flavor, or the number of virtual CPUs
|
|
||||||
available to the flavor, or both. When specifying multiple filters,
|
|
||||||
*ALL* filters must match on a flavor before that flavor is returned as
|
|
||||||
a fact.
|
|
||||||
- This module was called C(os_flavor_facts) before Ansible 2.9, returning C(ansible_facts).
|
|
||||||
Note that the M(os_flavor_info) module no longer returns C(ansible_facts)!
|
|
||||||
notes:
|
|
||||||
- The result contains a list of unsorted flavors.
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- A flavor name. Cannot be used with I(ram) or I(vcpus) or I(ephemeral).
|
|
||||||
type: str
|
|
||||||
ram:
|
|
||||||
description:
|
|
||||||
- "A string used for filtering flavors based on the amount of RAM
|
|
||||||
(in MB) desired. This string accepts the following special values:
|
|
||||||
'MIN' (return flavors with the minimum amount of RAM), and 'MAX'
|
|
||||||
(return flavors with the maximum amount of RAM)."
|
|
||||||
|
|
||||||
- "A specific amount of RAM may also be specified. Any flavors with this
|
|
||||||
exact amount of RAM will be returned."
|
|
||||||
|
|
||||||
- "A range of acceptable RAM may be given using a special syntax. Simply
|
|
||||||
prefix the amount of RAM with one of these acceptable range values:
|
|
||||||
'<', '>', '<=', '>='. These values represent less than, greater than,
|
|
||||||
less than or equal to, and greater than or equal to, respectively."
|
|
||||||
type: str
|
|
||||||
vcpus:
|
|
||||||
description:
|
|
||||||
- A string used for filtering flavors based on the number of virtual
|
|
||||||
CPUs desired. Format is the same as the I(ram) parameter.
|
|
||||||
type: str
|
|
||||||
limit:
|
|
||||||
description:
|
|
||||||
- Limits the number of flavors returned. All matching flavors are
|
|
||||||
returned by default.
|
|
||||||
type: int
|
|
||||||
ephemeral:
|
|
||||||
description:
|
|
||||||
- A string used for filtering flavors based on the amount of ephemeral
|
|
||||||
storage. Format is the same as the I(ram) parameter
|
|
||||||
type: str
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Gather information about all available flavors
|
|
||||||
- os_flavor_info:
|
|
||||||
cloud: mycloud
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- debug:
|
|
||||||
msg: "{{ result.openstack_flavors }}"
|
|
||||||
|
|
||||||
# Gather information for the flavor named "xlarge-flavor"
|
|
||||||
- os_flavor_info:
|
|
||||||
cloud: mycloud
|
|
||||||
name: "xlarge-flavor"
|
|
||||||
|
|
||||||
# Get all flavors that have exactly 512 MB of RAM.
|
|
||||||
- os_flavor_info:
|
|
||||||
cloud: mycloud
|
|
||||||
ram: "512"
|
|
||||||
|
|
||||||
# Get all flavors that have 1024 MB or more of RAM.
|
|
||||||
- os_flavor_info:
|
|
||||||
cloud: mycloud
|
|
||||||
ram: ">=1024"
|
|
||||||
|
|
||||||
# Get a single flavor that has the minimum amount of RAM. Using the 'limit'
|
|
||||||
# option will guarantee only a single flavor is returned.
|
|
||||||
- os_flavor_info:
|
|
||||||
cloud: mycloud
|
|
||||||
ram: "MIN"
|
|
||||||
limit: 1
|
|
||||||
|
|
||||||
# Get all flavors with 1024 MB of RAM or more, AND exactly 2 virtual CPUs.
|
|
||||||
- os_flavor_info:
|
|
||||||
cloud: mycloud
|
|
||||||
ram: ">=1024"
|
|
||||||
vcpus: "2"
|
|
||||||
|
|
||||||
# Get all flavors with 1024 MB of RAM or more, exactly 2 virtual CPUs, and
|
|
||||||
# less than 30gb of ephemeral storage.
|
|
||||||
- os_flavor_info:
|
|
||||||
cloud: mycloud
|
|
||||||
ram: ">=1024"
|
|
||||||
vcpus: "2"
|
|
||||||
ephemeral: "<30"
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
openstack_flavors:
|
|
||||||
description: Dictionary describing the flavors.
|
|
||||||
returned: On success.
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
id:
|
|
||||||
description: Flavor ID.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
sample: "515256b8-7027-4d73-aa54-4e30a4a4a339"
|
|
||||||
name:
|
|
||||||
description: Flavor name.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
sample: "tiny"
|
|
||||||
disk:
|
|
||||||
description: Size of local disk, in GB.
|
|
||||||
returned: success
|
|
||||||
type: int
|
|
||||||
sample: 10
|
|
||||||
ephemeral:
|
|
||||||
description: Ephemeral space size, in GB.
|
|
||||||
returned: success
|
|
||||||
type: int
|
|
||||||
sample: 10
|
|
||||||
ram:
|
|
||||||
description: Amount of memory, in MB.
|
|
||||||
returned: success
|
|
||||||
type: int
|
|
||||||
sample: 1024
|
|
||||||
swap:
|
|
||||||
description: Swap space size, in MB.
|
|
||||||
returned: success
|
|
||||||
type: int
|
|
||||||
sample: 100
|
|
||||||
vcpus:
|
|
||||||
description: Number of virtual CPUs.
|
|
||||||
returned: success
|
|
||||||
type: int
|
|
||||||
sample: 2
|
|
||||||
is_public:
|
|
||||||
description: Make flavor accessible to the public.
|
|
||||||
returned: success
|
|
||||||
type: bool
|
|
||||||
sample: true
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
name=dict(required=False, default=None),
|
|
||||||
ram=dict(required=False, default=None),
|
|
||||||
vcpus=dict(required=False, default=None),
|
|
||||||
limit=dict(required=False, default=None, type='int'),
|
|
||||||
ephemeral=dict(required=False, default=None),
|
|
||||||
)
|
|
||||||
module_kwargs = openstack_module_kwargs(
|
|
||||||
mutually_exclusive=[
|
|
||||||
['name', 'ram'],
|
|
||||||
['name', 'vcpus'],
|
|
||||||
['name', 'ephemeral']
|
|
||||||
]
|
|
||||||
)
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
is_old_facts = module._name == 'os_flavor_facts'
|
|
||||||
if is_old_facts:
|
|
||||||
module.deprecate("The 'os_flavor_facts' module has been renamed to 'os_flavor_info', "
|
|
||||||
"and the renamed one no longer returns ansible_facts", version='2.13')
|
|
||||||
|
|
||||||
name = module.params['name']
|
|
||||||
vcpus = module.params['vcpus']
|
|
||||||
ram = module.params['ram']
|
|
||||||
ephemeral = module.params['ephemeral']
|
|
||||||
limit = module.params['limit']
|
|
||||||
|
|
||||||
filters = {}
|
|
||||||
if vcpus:
|
|
||||||
filters['vcpus'] = vcpus
|
|
||||||
if ram:
|
|
||||||
filters['ram'] = ram
|
|
||||||
if ephemeral:
|
|
||||||
filters['ephemeral'] = ephemeral
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
if name:
|
|
||||||
flavors = cloud.search_flavors(filters={'name': name})
|
|
||||||
|
|
||||||
else:
|
|
||||||
flavors = cloud.list_flavors()
|
|
||||||
if filters:
|
|
||||||
flavors = cloud.range_search(flavors, filters)
|
|
||||||
|
|
||||||
if limit is not None:
|
|
||||||
flavors = flavors[:limit]
|
|
||||||
|
|
||||||
if is_old_facts:
|
|
||||||
module.exit_json(changed=False,
|
|
||||||
ansible_facts=dict(openstack_flavors=flavors))
|
|
||||||
else:
|
|
||||||
module.exit_json(changed=False,
|
|
||||||
openstack_flavors=flavors)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_flavor_info.py
Symbolic link
1
plugins/modules/os_flavor_info.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
compute_flavor_info.py
|
@ -1,261 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright: (c) 2015, Hewlett-Packard Development Company, L.P.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_floating_ip
|
|
||||||
author: Davide Guerri (@dguerri) <davide.guerri@hp.com>
|
|
||||||
short_description: Add/Remove floating IP from an instance
|
|
||||||
description:
|
|
||||||
- Add or Remove a floating IP to an instance.
|
|
||||||
- Returns the floating IP when attaching only if I(wait=true).
|
|
||||||
options:
|
|
||||||
server:
|
|
||||||
description:
|
|
||||||
- The name or ID of the instance to which the IP address
|
|
||||||
should be assigned.
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
network:
|
|
||||||
description:
|
|
||||||
- The name or ID of a neutron external network or a nova pool name.
|
|
||||||
type: str
|
|
||||||
floating_ip_address:
|
|
||||||
description:
|
|
||||||
- A floating IP address to attach or to detach. Required only if I(state)
|
|
||||||
is absent. When I(state) is present can be used to specify a IP address
|
|
||||||
to attach.
|
|
||||||
type: str
|
|
||||||
reuse:
|
|
||||||
description:
|
|
||||||
- When I(state) is present, and I(floating_ip_address) is not present,
|
|
||||||
this parameter can be used to specify whether we should try to reuse
|
|
||||||
a floating IP address already allocated to the project.
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
fixed_address:
|
|
||||||
description:
|
|
||||||
- To which fixed IP of server the floating IP address should be
|
|
||||||
attached to.
|
|
||||||
type: str
|
|
||||||
nat_destination:
|
|
||||||
description:
|
|
||||||
- The name or id of a neutron private network that the fixed IP to
|
|
||||||
attach floating IP is on
|
|
||||||
aliases: ["fixed_network", "internal_network"]
|
|
||||||
type: str
|
|
||||||
wait:
|
|
||||||
description:
|
|
||||||
- When attaching a floating IP address, specify whether to wait for it to appear as attached.
|
|
||||||
- Must be set to C(yes) for the module to return the value of the floating IP.
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
timeout:
|
|
||||||
description:
|
|
||||||
- Time to wait for an IP address to appear as attached. See wait.
|
|
||||||
required: false
|
|
||||||
default: 60
|
|
||||||
type: int
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Should the resource be present or absent.
|
|
||||||
choices: [present, absent]
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
purge:
|
|
||||||
description:
|
|
||||||
- When I(state) is absent, indicates whether or not to delete the floating
|
|
||||||
IP completely, or only detach it from the server. Default is to detach only.
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Assign a floating IP to the fist interface of `cattle001` from an exiting
|
|
||||||
# external network or nova pool. A new floating IP from the first available
|
|
||||||
# external network is allocated to the project.
|
|
||||||
- os_floating_ip:
|
|
||||||
cloud: dguerri
|
|
||||||
server: cattle001
|
|
||||||
|
|
||||||
# Assign a new floating IP to the instance fixed ip `192.0.2.3` of
|
|
||||||
# `cattle001`. If a free floating IP is already allocated to the project, it is
|
|
||||||
# reused; if not, a new one is created.
|
|
||||||
- os_floating_ip:
|
|
||||||
cloud: dguerri
|
|
||||||
state: present
|
|
||||||
reuse: yes
|
|
||||||
server: cattle001
|
|
||||||
network: ext_net
|
|
||||||
fixed_address: 192.0.2.3
|
|
||||||
wait: true
|
|
||||||
timeout: 180
|
|
||||||
|
|
||||||
# Assign a new floating IP from the network `ext_net` to the instance fixed
|
|
||||||
# ip in network `private_net` of `cattle001`.
|
|
||||||
- os_floating_ip:
|
|
||||||
cloud: dguerri
|
|
||||||
state: present
|
|
||||||
server: cattle001
|
|
||||||
network: ext_net
|
|
||||||
nat_destination: private_net
|
|
||||||
wait: true
|
|
||||||
timeout: 180
|
|
||||||
|
|
||||||
# Detach a floating IP address from a server
|
|
||||||
- os_floating_ip:
|
|
||||||
cloud: dguerri
|
|
||||||
state: absent
|
|
||||||
floating_ip_address: 203.0.113.2
|
|
||||||
server: cattle001
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule, remove_values
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _get_floating_ip(cloud, floating_ip_address):
|
|
||||||
f_ips = cloud.search_floating_ips(
|
|
||||||
filters={'floating_ip_address': floating_ip_address})
|
|
||||||
if not f_ips:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return f_ips[0]
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
server=dict(required=True),
|
|
||||||
state=dict(default='present', choices=['absent', 'present']),
|
|
||||||
network=dict(required=False, default=None),
|
|
||||||
floating_ip_address=dict(required=False, default=None),
|
|
||||||
reuse=dict(required=False, type='bool', default=False),
|
|
||||||
fixed_address=dict(required=False, default=None),
|
|
||||||
nat_destination=dict(required=False, default=None,
|
|
||||||
aliases=['fixed_network', 'internal_network']),
|
|
||||||
wait=dict(required=False, type='bool', default=False),
|
|
||||||
timeout=dict(required=False, type='int', default=60),
|
|
||||||
purge=dict(required=False, type='bool', default=False),
|
|
||||||
)
|
|
||||||
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
|
|
||||||
server_name_or_id = module.params['server']
|
|
||||||
state = module.params['state']
|
|
||||||
network = module.params['network']
|
|
||||||
floating_ip_address = module.params['floating_ip_address']
|
|
||||||
reuse = module.params['reuse']
|
|
||||||
fixed_address = module.params['fixed_address']
|
|
||||||
nat_destination = module.params['nat_destination']
|
|
||||||
wait = module.params['wait']
|
|
||||||
timeout = module.params['timeout']
|
|
||||||
purge = module.params['purge']
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
|
|
||||||
server = cloud.get_server(server_name_or_id)
|
|
||||||
if server is None:
|
|
||||||
module.fail_json(
|
|
||||||
msg="server {0} not found".format(server_name_or_id))
|
|
||||||
|
|
||||||
if state == 'present':
|
|
||||||
# If f_ip already assigned to server, check that it matches
|
|
||||||
# requirements.
|
|
||||||
public_ip = cloud.get_server_public_ip(server)
|
|
||||||
f_ip = _get_floating_ip(cloud, public_ip) if public_ip else public_ip
|
|
||||||
if f_ip:
|
|
||||||
if network:
|
|
||||||
network_id = cloud.get_network(name_or_id=network)["id"]
|
|
||||||
else:
|
|
||||||
network_id = None
|
|
||||||
# check if we have floating ip on given nat_destination network
|
|
||||||
if nat_destination:
|
|
||||||
nat_floating_addrs = [
|
|
||||||
addr for addr in server.addresses.get(
|
|
||||||
cloud.get_network(nat_destination)['name'], [])
|
|
||||||
if addr['addr'] == public_ip
|
|
||||||
and addr['OS-EXT-IPS:type'] == 'floating'
|
|
||||||
]
|
|
||||||
|
|
||||||
if len(nat_floating_addrs) == 0:
|
|
||||||
module.fail_json(msg="server {server} already has a "
|
|
||||||
"floating-ip on a different "
|
|
||||||
"nat-destination than '{nat_destination}'"
|
|
||||||
.format(server=server_name_or_id,
|
|
||||||
nat_destination=nat_destination))
|
|
||||||
|
|
||||||
if all([fixed_address, f_ip.fixed_ip_address == fixed_address,
|
|
||||||
network, f_ip.network != network_id]):
|
|
||||||
# Current state definitely conflicts with requirements
|
|
||||||
module.fail_json(msg="server {server} already has a "
|
|
||||||
"floating-ip on requested "
|
|
||||||
"interface but it doesn't match "
|
|
||||||
"requested network {network}: {fip}"
|
|
||||||
.format(server=server_name_or_id,
|
|
||||||
network=network,
|
|
||||||
fip=remove_values(f_ip,
|
|
||||||
module.no_log_values)))
|
|
||||||
if not network or f_ip.network == network_id:
|
|
||||||
# Requirements are met
|
|
||||||
module.exit_json(changed=False, floating_ip=f_ip)
|
|
||||||
|
|
||||||
# Requirements are vague enough to ignore existing f_ip and try
|
|
||||||
# to create a new f_ip to the server.
|
|
||||||
|
|
||||||
server = cloud.add_ips_to_server(
|
|
||||||
server=server, ips=floating_ip_address, ip_pool=network,
|
|
||||||
reuse=reuse, fixed_address=fixed_address, wait=wait,
|
|
||||||
timeout=timeout, nat_destination=nat_destination)
|
|
||||||
fip_address = cloud.get_server_public_ip(server)
|
|
||||||
# Update the floating IP status
|
|
||||||
f_ip = _get_floating_ip(cloud, fip_address)
|
|
||||||
module.exit_json(changed=True, floating_ip=f_ip)
|
|
||||||
|
|
||||||
elif state == 'absent':
|
|
||||||
if floating_ip_address is None:
|
|
||||||
if not server_name_or_id:
|
|
||||||
module.fail_json(msg="either server or floating_ip_address are required")
|
|
||||||
server = cloud.get_server(server_name_or_id)
|
|
||||||
floating_ip_address = cloud.get_server_public_ip(server)
|
|
||||||
|
|
||||||
f_ip = _get_floating_ip(cloud, floating_ip_address)
|
|
||||||
|
|
||||||
if not f_ip:
|
|
||||||
# Nothing to detach
|
|
||||||
module.exit_json(changed=False)
|
|
||||||
changed = False
|
|
||||||
if f_ip["fixed_ip_address"]:
|
|
||||||
cloud.detach_ip_from_server(
|
|
||||||
server_id=server['id'], floating_ip_id=f_ip['id'])
|
|
||||||
# Update the floating IP status
|
|
||||||
f_ip = cloud.get_floating_ip(id=f_ip['id'])
|
|
||||||
changed = True
|
|
||||||
if purge:
|
|
||||||
cloud.delete_floating_ip(f_ip['id'])
|
|
||||||
module.exit_json(changed=True)
|
|
||||||
module.exit_json(changed=changed, floating_ip=f_ip)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_floating_ip.py
Symbolic link
1
plugins/modules/os_floating_ip.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
floating_ip.py
|
@ -1,167 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# Copyright (c) 2016 IBM
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_group
|
|
||||||
short_description: Manage OpenStack Identity Groups
|
|
||||||
author: "Monty Taylor (@emonty), David Shrewsbury (@Shrews)"
|
|
||||||
description:
|
|
||||||
- Manage OpenStack Identity Groups. Groups can be created, deleted or
|
|
||||||
updated. Only the I(description) value can be updated.
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Group name
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
description:
|
|
||||||
- Group description
|
|
||||||
type: str
|
|
||||||
domain_id:
|
|
||||||
description:
|
|
||||||
- Domain id to create the group in if the cloud supports domains.
|
|
||||||
type: str
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Should the resource be present or absent.
|
|
||||||
choices: [present, absent]
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Create a group named "demo"
|
|
||||||
- os_group:
|
|
||||||
cloud: mycloud
|
|
||||||
state: present
|
|
||||||
name: demo
|
|
||||||
description: "Demo Group"
|
|
||||||
domain_id: demoid
|
|
||||||
|
|
||||||
# Update the description on existing "demo" group
|
|
||||||
- os_group:
|
|
||||||
cloud: mycloud
|
|
||||||
state: present
|
|
||||||
name: demo
|
|
||||||
description: "Something else"
|
|
||||||
domain_id: demoid
|
|
||||||
|
|
||||||
# Delete group named "demo"
|
|
||||||
- os_group:
|
|
||||||
cloud: mycloud
|
|
||||||
state: absent
|
|
||||||
name: demo
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
group:
|
|
||||||
description: Dictionary describing the group.
|
|
||||||
returned: On success when I(state) is 'present'.
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
id:
|
|
||||||
description: Unique group ID
|
|
||||||
type: str
|
|
||||||
sample: "ee6156ff04c645f481a6738311aea0b0"
|
|
||||||
name:
|
|
||||||
description: Group name
|
|
||||||
type: str
|
|
||||||
sample: "demo"
|
|
||||||
description:
|
|
||||||
description: Group description
|
|
||||||
type: str
|
|
||||||
sample: "Demo Group"
|
|
||||||
domain_id:
|
|
||||||
description: Domain for the group
|
|
||||||
type: str
|
|
||||||
sample: "default"
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _system_state_change(state, description, group):
|
|
||||||
if state == 'present' and not group:
|
|
||||||
return True
|
|
||||||
if state == 'present' and description is not None and group.description != description:
|
|
||||||
return True
|
|
||||||
if state == 'absent' and group:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
name=dict(required=True),
|
|
||||||
description=dict(required=False, default=None),
|
|
||||||
domain_id=dict(required=False, default=None),
|
|
||||||
state=dict(default='present', choices=['absent', 'present']),
|
|
||||||
)
|
|
||||||
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec,
|
|
||||||
supports_check_mode=True,
|
|
||||||
**module_kwargs)
|
|
||||||
|
|
||||||
name = module.params.get('name')
|
|
||||||
description = module.params.get('description')
|
|
||||||
state = module.params.get('state')
|
|
||||||
|
|
||||||
domain_id = module.params.pop('domain_id')
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
if domain_id:
|
|
||||||
group = cloud.get_group(name, filters={'domain_id': domain_id})
|
|
||||||
else:
|
|
||||||
group = cloud.get_group(name)
|
|
||||||
|
|
||||||
if module.check_mode:
|
|
||||||
module.exit_json(changed=_system_state_change(state, description, group))
|
|
||||||
|
|
||||||
if state == 'present':
|
|
||||||
if group is None:
|
|
||||||
group = cloud.create_group(
|
|
||||||
name=name, description=description, domain=domain_id)
|
|
||||||
changed = True
|
|
||||||
else:
|
|
||||||
if description is not None and group.description != description:
|
|
||||||
group = cloud.update_group(
|
|
||||||
group.id, description=description)
|
|
||||||
changed = True
|
|
||||||
else:
|
|
||||||
changed = False
|
|
||||||
module.exit_json(changed=changed, group=group)
|
|
||||||
|
|
||||||
elif state == 'absent':
|
|
||||||
if group is None:
|
|
||||||
changed = False
|
|
||||||
else:
|
|
||||||
cloud.delete_group(group.id)
|
|
||||||
changed = True
|
|
||||||
module.exit_json(changed=changed)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_group.py
Symbolic link
1
plugins/modules/os_group.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
identity_group.py
|
@ -1,164 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2019, Phillipe Smith <phillipelnx@gmail.com>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_group_info
|
|
||||||
short_description: Retrieve info about one or more OpenStack groups
|
|
||||||
author: "Phillipe Smith (@phsmith)"
|
|
||||||
description:
|
|
||||||
- Retrieve info about a one or more OpenStack groups.
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name or ID of the group.
|
|
||||||
type: str
|
|
||||||
domain:
|
|
||||||
description:
|
|
||||||
- Name or ID of the domain containing the group if the cloud supports domains
|
|
||||||
type: str
|
|
||||||
filters:
|
|
||||||
description:
|
|
||||||
- A dictionary of meta data to use for further filtering. Elements of
|
|
||||||
this dictionary may be additional dictionaries.
|
|
||||||
type: dict
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Gather info about previously created groups
|
|
||||||
- name: gather info
|
|
||||||
hosts: localhost
|
|
||||||
tasks:
|
|
||||||
- name: Gather info about previously created groups
|
|
||||||
os_group_info:
|
|
||||||
cloud: awesomecloud
|
|
||||||
register: openstack_groups
|
|
||||||
- debug:
|
|
||||||
var: openstack_groups
|
|
||||||
|
|
||||||
# Gather info about a previously created group by name
|
|
||||||
- name: gather info
|
|
||||||
hosts: localhost
|
|
||||||
tasks:
|
|
||||||
- name: Gather info about a previously created group by name
|
|
||||||
os_group_info:
|
|
||||||
cloud: awesomecloud
|
|
||||||
name: demogroup
|
|
||||||
register: openstack_groups
|
|
||||||
- debug:
|
|
||||||
var: openstack_groups
|
|
||||||
|
|
||||||
# Gather info about a previously created group in a specific domain
|
|
||||||
- name: gather info
|
|
||||||
hosts: localhost
|
|
||||||
tasks:
|
|
||||||
- name: Gather info about a previously created group in a specific domain
|
|
||||||
os_group_info:
|
|
||||||
cloud: awesomecloud
|
|
||||||
name: demogroup
|
|
||||||
domain: admindomain
|
|
||||||
register: openstack_groups
|
|
||||||
- debug:
|
|
||||||
var: openstack_groups
|
|
||||||
|
|
||||||
# Gather info about a previously created group in a specific domain with filter
|
|
||||||
- name: gather info
|
|
||||||
hosts: localhost
|
|
||||||
tasks:
|
|
||||||
- name: Gather info about a previously created group in a specific domain with filter
|
|
||||||
os_group_info:
|
|
||||||
cloud: awesomecloud
|
|
||||||
name: demogroup
|
|
||||||
domain: admindomain
|
|
||||||
filters:
|
|
||||||
enabled: False
|
|
||||||
register: openstack_groups
|
|
||||||
- debug:
|
|
||||||
var: openstack_groups
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
openstack_groups:
|
|
||||||
description: Dictionary describing all the matching groups.
|
|
||||||
returned: always, but can be null
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
name:
|
|
||||||
description: Name given to the group.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
description: Description of the group.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
id:
|
|
||||||
description: Unique UUID.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
domain_id:
|
|
||||||
description: Domain ID containing the group (keystone v3 clouds only)
|
|
||||||
returned: success
|
|
||||||
type: bool
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import openstack_full_argument_spec, openstack_cloud_from_module
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
name=dict(required=False, default=None),
|
|
||||||
domain=dict(required=False, default=None),
|
|
||||||
filters=dict(required=False, type='dict', default=None),
|
|
||||||
)
|
|
||||||
|
|
||||||
module = AnsibleModule(argument_spec)
|
|
||||||
|
|
||||||
sdk, opcloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
name = module.params['name']
|
|
||||||
domain = module.params['domain']
|
|
||||||
filters = module.params['filters']
|
|
||||||
|
|
||||||
if domain:
|
|
||||||
try:
|
|
||||||
# We assume admin is passing domain id
|
|
||||||
dom = opcloud.get_domain(domain)['id']
|
|
||||||
domain = dom
|
|
||||||
except Exception:
|
|
||||||
# If we fail, maybe admin is passing a domain name.
|
|
||||||
# Note that domains have unique names, just like id.
|
|
||||||
dom = opcloud.search_domains(filters={'name': domain})
|
|
||||||
if dom:
|
|
||||||
domain = dom[0]['id']
|
|
||||||
else:
|
|
||||||
module.fail_json(msg='Domain name or ID does not exist')
|
|
||||||
|
|
||||||
if not filters:
|
|
||||||
filters = {}
|
|
||||||
|
|
||||||
groups = opcloud.search_groups(name, filters, domain_id=domain)
|
|
||||||
module.exit_json(changed=False, groups=groups)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_group_info.py
Symbolic link
1
plugins/modules/os_group_info.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
identity_group_info.py
|
@ -1,246 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
|
||||||
# Copyright (c) 2013, Benno Joy <benno@ansible.com>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO(mordred): we need to support "location"(v1) and "locations"(v2)
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_image
|
|
||||||
short_description: Add/Delete images from OpenStack Cloud
|
|
||||||
author: "Monty Taylor (@emonty)"
|
|
||||||
description:
|
|
||||||
- Add or Remove images from the OpenStack Image Repository
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- The name of the image when uploading - or the name/ID of the image if deleting
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
id:
|
|
||||||
description:
|
|
||||||
- The ID of the image when uploading an image
|
|
||||||
type: str
|
|
||||||
checksum:
|
|
||||||
description:
|
|
||||||
- The checksum of the image
|
|
||||||
type: str
|
|
||||||
disk_format:
|
|
||||||
description:
|
|
||||||
- The format of the disk that is getting uploaded
|
|
||||||
default: qcow2
|
|
||||||
choices: ['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso', 'vhdx', 'ploop']
|
|
||||||
type: str
|
|
||||||
container_format:
|
|
||||||
description:
|
|
||||||
- The format of the container
|
|
||||||
default: bare
|
|
||||||
choices: ['ami', 'aki', 'ari', 'bare', 'ovf', 'ova', 'docker']
|
|
||||||
type: str
|
|
||||||
owner:
|
|
||||||
description:
|
|
||||||
- The owner of the image
|
|
||||||
type: str
|
|
||||||
min_disk:
|
|
||||||
description:
|
|
||||||
- The minimum disk space (in GB) required to boot this image
|
|
||||||
type: int
|
|
||||||
min_ram:
|
|
||||||
description:
|
|
||||||
- The minimum ram (in MB) required to boot this image
|
|
||||||
type: int
|
|
||||||
is_public:
|
|
||||||
description:
|
|
||||||
- Whether the image can be accessed publicly. Note that publicizing an image requires admin role by default.
|
|
||||||
type: bool
|
|
||||||
default: false
|
|
||||||
protected:
|
|
||||||
description:
|
|
||||||
- Prevent image from being deleted
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
filename:
|
|
||||||
description:
|
|
||||||
- The path to the file which has to be uploaded
|
|
||||||
type: str
|
|
||||||
ramdisk:
|
|
||||||
description:
|
|
||||||
- The name of an existing ramdisk image that will be associated with this image
|
|
||||||
type: str
|
|
||||||
kernel:
|
|
||||||
description:
|
|
||||||
- The name of an existing kernel image that will be associated with this image
|
|
||||||
type: str
|
|
||||||
properties:
|
|
||||||
description:
|
|
||||||
- Additional properties to be associated with this image
|
|
||||||
default: {}
|
|
||||||
type: dict
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Should the resource be present or absent.
|
|
||||||
choices: [present, absent]
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
volume:
|
|
||||||
description:
|
|
||||||
- ID of a volume to create an image from.
|
|
||||||
- The volume must be in AVAILABLE state.
|
|
||||||
type: str
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Upload an image from a local file named cirros-0.3.0-x86_64-disk.img
|
|
||||||
- os_image:
|
|
||||||
auth:
|
|
||||||
auth_url: https://identity.example.com
|
|
||||||
username: admin
|
|
||||||
password: passme
|
|
||||||
project_name: admin
|
|
||||||
os_user_domain_name: Default
|
|
||||||
os_project_domain_name: Default
|
|
||||||
name: cirros
|
|
||||||
container_format: bare
|
|
||||||
disk_format: qcow2
|
|
||||||
state: present
|
|
||||||
filename: cirros-0.3.0-x86_64-disk.img
|
|
||||||
kernel: cirros-vmlinuz
|
|
||||||
ramdisk: cirros-initrd
|
|
||||||
properties:
|
|
||||||
cpu_arch: x86_64
|
|
||||||
distro: ubuntu
|
|
||||||
|
|
||||||
# Create image from volume attached to an instance
|
|
||||||
- name: create volume snapshot
|
|
||||||
os_volume_snapshot:
|
|
||||||
auth:
|
|
||||||
"{{ auth }}"
|
|
||||||
display_name: myvol_snapshot
|
|
||||||
volume: myvol
|
|
||||||
force: yes
|
|
||||||
register: myvol_snapshot
|
|
||||||
|
|
||||||
- name: create volume from snapshot
|
|
||||||
os_volume:
|
|
||||||
auth:
|
|
||||||
"{{ auth }}"
|
|
||||||
size: "{{ myvol_snapshot.snapshot.size }}"
|
|
||||||
snapshot_id: "{{ myvol_snapshot.snapshot.id }}"
|
|
||||||
display_name: myvol_snapshot_volume
|
|
||||||
wait: yes
|
|
||||||
register: myvol_snapshot_volume
|
|
||||||
|
|
||||||
- name: create image from volume snapshot
|
|
||||||
os_image:
|
|
||||||
auth:
|
|
||||||
"{{ auth }}"
|
|
||||||
volume: "{{ myvol_snapshot_volume.volume.id }}"
|
|
||||||
name: myvol_image
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
name=dict(required=True),
|
|
||||||
id=dict(default=None),
|
|
||||||
checksum=dict(default=None),
|
|
||||||
disk_format=dict(default='qcow2', choices=['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', 'vdi', 'iso', 'vhdx', 'ploop']),
|
|
||||||
container_format=dict(default='bare', choices=['ami', 'aki', 'ari', 'bare', 'ovf', 'ova', 'docker']),
|
|
||||||
owner=dict(default=None),
|
|
||||||
min_disk=dict(type='int', default=0),
|
|
||||||
min_ram=dict(type='int', default=0),
|
|
||||||
is_public=dict(type='bool', default=False),
|
|
||||||
protected=dict(type='bool', default=False),
|
|
||||||
filename=dict(default=None),
|
|
||||||
ramdisk=dict(default=None),
|
|
||||||
kernel=dict(default=None),
|
|
||||||
properties=dict(type='dict', default={}),
|
|
||||||
volume=dict(default=None),
|
|
||||||
state=dict(default='present', choices=['absent', 'present']),
|
|
||||||
)
|
|
||||||
|
|
||||||
module_kwargs = openstack_module_kwargs(
|
|
||||||
mutually_exclusive=[['filename', 'volume']],
|
|
||||||
)
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
|
|
||||||
changed = False
|
|
||||||
if module.params['id']:
|
|
||||||
image = cloud.get_image(name_or_id=module.params['id'])
|
|
||||||
elif module.params['checksum']:
|
|
||||||
image = cloud.get_image(name_or_id=module.params['name'], filters={'checksum': module.params['checksum']})
|
|
||||||
else:
|
|
||||||
image = cloud.get_image(name_or_id=module.params['name'])
|
|
||||||
|
|
||||||
if module.params['state'] == 'present':
|
|
||||||
if not image:
|
|
||||||
kwargs = {}
|
|
||||||
if module.params['id'] is not None:
|
|
||||||
kwargs['id'] = module.params['id']
|
|
||||||
image = cloud.create_image(
|
|
||||||
name=module.params['name'],
|
|
||||||
filename=module.params['filename'],
|
|
||||||
disk_format=module.params['disk_format'],
|
|
||||||
container_format=module.params['container_format'],
|
|
||||||
wait=module.params['wait'],
|
|
||||||
timeout=module.params['timeout'],
|
|
||||||
is_public=module.params['is_public'],
|
|
||||||
protected=module.params['protected'],
|
|
||||||
min_disk=module.params['min_disk'],
|
|
||||||
min_ram=module.params['min_ram'],
|
|
||||||
volume=module.params['volume'],
|
|
||||||
**kwargs
|
|
||||||
)
|
|
||||||
changed = True
|
|
||||||
if not module.params['wait']:
|
|
||||||
module.exit_json(changed=changed, image=image, id=image.id)
|
|
||||||
|
|
||||||
cloud.update_image_properties(
|
|
||||||
image=image,
|
|
||||||
kernel=module.params['kernel'],
|
|
||||||
ramdisk=module.params['ramdisk'],
|
|
||||||
protected=module.params['protected'],
|
|
||||||
**module.params['properties'])
|
|
||||||
image = cloud.get_image(name_or_id=image.id)
|
|
||||||
module.exit_json(changed=changed, image=image, id=image.id)
|
|
||||||
|
|
||||||
elif module.params['state'] == 'absent':
|
|
||||||
if not image:
|
|
||||||
changed = False
|
|
||||||
else:
|
|
||||||
cloud.delete_image(
|
|
||||||
name_or_id=module.params['name'],
|
|
||||||
wait=module.params['wait'],
|
|
||||||
timeout=module.params['timeout'])
|
|
||||||
changed = True
|
|
||||||
module.exit_json(changed=changed)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e), extra_data=e.extra_data)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
1
plugins/modules/os_image.py
Symbolic link
1
plugins/modules/os_image.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
image.py
|
@ -1,192 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
module: os_image_info
|
|
||||||
short_description: Retrieve information about an image within OpenStack.
|
|
||||||
author: "Davide Agnello (@dagnello)"
|
|
||||||
description:
|
|
||||||
- Retrieve information about a image image from OpenStack.
|
|
||||||
- This module was called C(os_image_facts) before Ansible 2.9, returning C(ansible_facts).
|
|
||||||
Note that the M(os_image_info) module no longer returns C(ansible_facts)!
|
|
||||||
options:
|
|
||||||
image:
|
|
||||||
description:
|
|
||||||
- Name or ID of the image
|
|
||||||
required: false
|
|
||||||
type: str
|
|
||||||
properties:
|
|
||||||
description:
|
|
||||||
- Dict of properties of the images used for query
|
|
||||||
type: dict
|
|
||||||
required: false
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
- name: Gather information about a previously created image named image1
|
|
||||||
os_image_info:
|
|
||||||
auth:
|
|
||||||
auth_url: https://identity.example.com
|
|
||||||
username: user
|
|
||||||
password: password
|
|
||||||
project_name: someproject
|
|
||||||
image: image1
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Show openstack information
|
|
||||||
debug:
|
|
||||||
msg: "{{ result.openstack_image }}"
|
|
||||||
|
|
||||||
# Show all available Openstack images
|
|
||||||
- name: Retrieve all available Openstack images
|
|
||||||
os_image_info:
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Show images
|
|
||||||
debug:
|
|
||||||
msg: "{{ result.openstack_image }}"
|
|
||||||
|
|
||||||
# Show images matching requested properties
|
|
||||||
- name: Retrieve images having properties with desired values
|
|
||||||
os_image_facts:
|
|
||||||
properties:
|
|
||||||
some_property: some_value
|
|
||||||
OtherProp: OtherVal
|
|
||||||
|
|
||||||
- name: Show images
|
|
||||||
debug:
|
|
||||||
msg: "{{ result.openstack_image }}"
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
openstack_image:
|
|
||||||
description: has all the openstack information about the image
|
|
||||||
returned: always, but can be null
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
id:
|
|
||||||
description: Unique UUID.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
name:
|
|
||||||
description: Name given to the image.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
status:
|
|
||||||
description: Image status.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
created_at:
|
|
||||||
description: Image created at timestamp.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
deleted:
|
|
||||||
description: Image deleted flag.
|
|
||||||
returned: success
|
|
||||||
type: bool
|
|
||||||
container_format:
|
|
||||||
description: Container format of the image.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
min_ram:
|
|
||||||
description: Min amount of RAM required for this image.
|
|
||||||
returned: success
|
|
||||||
type: int
|
|
||||||
disk_format:
|
|
||||||
description: Disk format of the image.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
updated_at:
|
|
||||||
description: Image updated at timestamp.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
properties:
|
|
||||||
description: Additional properties associated with the image.
|
|
||||||
returned: success
|
|
||||||
type: dict
|
|
||||||
min_disk:
|
|
||||||
description: Min amount of disk space required for this image.
|
|
||||||
returned: success
|
|
||||||
type: int
|
|
||||||
protected:
|
|
||||||
description: Image protected flag.
|
|
||||||
returned: success
|
|
||||||
type: bool
|
|
||||||
checksum:
|
|
||||||
description: Checksum for the image.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
owner:
|
|
||||||
description: Owner for the image.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
is_public:
|
|
||||||
description: Is public flag of the image.
|
|
||||||
returned: success
|
|
||||||
type: bool
|
|
||||||
deleted_at:
|
|
||||||
description: Image deleted at timestamp.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
size:
|
|
||||||
description: Size of the image.
|
|
||||||
returned: success
|
|
||||||
type: int
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
image=dict(required=False),
|
|
||||||
properties=dict(default=None, type='dict'),
|
|
||||||
)
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
is_old_facts = module._name == 'os_image_facts'
|
|
||||||
if is_old_facts:
|
|
||||||
module.deprecate("The 'os_image_facts' module has been renamed to 'os_image_info', "
|
|
||||||
"and the renamed one no longer returns ansible_facts", version='2.13')
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
if module.params['image']:
|
|
||||||
image = cloud.get_image(module.params['image'])
|
|
||||||
if is_old_facts:
|
|
||||||
module.exit_json(changed=False, ansible_facts=dict(
|
|
||||||
openstack_image=image))
|
|
||||||
else:
|
|
||||||
module.exit_json(changed=False, openstack_image=image)
|
|
||||||
else:
|
|
||||||
images = cloud.search_images(filters=module.params['properties'])
|
|
||||||
if is_old_facts:
|
|
||||||
module.exit_json(changed=False, ansible_facts=dict(
|
|
||||||
openstack_image=images))
|
|
||||||
else:
|
|
||||||
module.exit_json(changed=False, openstack_image=images)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_image_info.py
Symbolic link
1
plugins/modules/os_image_info.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
image_info.py
|
@ -1,380 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# coding: utf-8 -*-
|
|
||||||
|
|
||||||
# (c) 2014, Hewlett-Packard Development Company, L.P.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_ironic
|
|
||||||
short_description: Create/Delete Bare Metal Resources from OpenStack
|
|
||||||
author: "Monty Taylor (@emonty)"
|
|
||||||
description:
|
|
||||||
- Create or Remove Ironic nodes from OpenStack.
|
|
||||||
options:
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Indicates desired state of the resource
|
|
||||||
choices: ['present', 'absent']
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
uuid:
|
|
||||||
description:
|
|
||||||
- globally unique identifier (UUID) to be given to the resource. Will
|
|
||||||
be auto-generated if not specified, and name is specified.
|
|
||||||
- Definition of a UUID will always take precedence to a name value.
|
|
||||||
type: str
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- unique name identifier to be given to the resource.
|
|
||||||
type: str
|
|
||||||
driver:
|
|
||||||
description:
|
|
||||||
- The name of the Ironic Driver to use with this node.
|
|
||||||
- Required when I(state=present)
|
|
||||||
type: str
|
|
||||||
chassis_uuid:
|
|
||||||
description:
|
|
||||||
- Associate the node with a pre-defined chassis.
|
|
||||||
type: str
|
|
||||||
ironic_url:
|
|
||||||
description:
|
|
||||||
- If noauth mode is utilized, this is required to be set to the
|
|
||||||
endpoint URL for the Ironic API. Use with "auth" and "auth_type"
|
|
||||||
settings set to None.
|
|
||||||
type: str
|
|
||||||
driver_info:
|
|
||||||
description:
|
|
||||||
- Information for this server's driver. Will vary based on which
|
|
||||||
driver is in use. Any sub-field which is populated will be validated
|
|
||||||
during creation.
|
|
||||||
required: true
|
|
||||||
type: dict
|
|
||||||
suboptions:
|
|
||||||
power:
|
|
||||||
description:
|
|
||||||
- Information necessary to turn this server on / off.
|
|
||||||
This often includes such things as IPMI username, password, and IP address.
|
|
||||||
required: true
|
|
||||||
deploy:
|
|
||||||
description:
|
|
||||||
- Information necessary to deploy this server directly, without using Nova. THIS IS NOT RECOMMENDED.
|
|
||||||
console:
|
|
||||||
description:
|
|
||||||
- Information necessary to connect to this server's serial console. Not all drivers support this.
|
|
||||||
management:
|
|
||||||
description:
|
|
||||||
- Information necessary to interact with this server's management interface. May be shared by power_info in some cases.
|
|
||||||
required: true
|
|
||||||
nics:
|
|
||||||
description:
|
|
||||||
- 'A list of network interface cards, eg, " - mac: aa:bb:cc:aa:bb:cc"'
|
|
||||||
required: true
|
|
||||||
type: list
|
|
||||||
elements: dict
|
|
||||||
suboptions:
|
|
||||||
mac:
|
|
||||||
description: The MAC address of the network interface card.
|
|
||||||
type: str
|
|
||||||
required: true
|
|
||||||
properties:
|
|
||||||
description:
|
|
||||||
- Definition of the physical characteristics of this server, used for scheduling purposes
|
|
||||||
type: dict
|
|
||||||
suboptions:
|
|
||||||
cpu_arch:
|
|
||||||
description:
|
|
||||||
- CPU architecture (x86_64, i686, ...)
|
|
||||||
default: x86_64
|
|
||||||
cpus:
|
|
||||||
description:
|
|
||||||
- Number of CPU cores this machine has
|
|
||||||
default: 1
|
|
||||||
ram:
|
|
||||||
description:
|
|
||||||
- amount of RAM this machine has, in MB
|
|
||||||
default: 1
|
|
||||||
disk_size:
|
|
||||||
description:
|
|
||||||
- size of first storage device in this machine (typically /dev/sda), in GB
|
|
||||||
default: 1
|
|
||||||
capabilities:
|
|
||||||
description:
|
|
||||||
- special capabilities for the node, such as boot_option, node_role etc
|
|
||||||
(see U(https://docs.openstack.org/ironic/latest/install/advanced.html)
|
|
||||||
for more information)
|
|
||||||
default: ""
|
|
||||||
root_device:
|
|
||||||
description:
|
|
||||||
- Root disk device hints for deployment.
|
|
||||||
- See U(https://docs.openstack.org/ironic/latest/install/advanced.html#specifying-the-disk-for-deployment-root-device-hints)
|
|
||||||
for allowed hints.
|
|
||||||
default: ""
|
|
||||||
skip_update_of_masked_password:
|
|
||||||
description:
|
|
||||||
- Allows the code that would assert changes to nodes to skip the
|
|
||||||
update if the change is a single line consisting of the password
|
|
||||||
field.
|
|
||||||
- As of Kilo, by default, passwords are always masked to API
|
|
||||||
requests, which means the logic as a result always attempts to
|
|
||||||
re-assert the password field.
|
|
||||||
- C(skip_update_of_driver_password) is deprecated alias and will be removed in 2.14.
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
aliases: [ skip_update_of_driver_password ]
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
- "jsonpatch"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Enroll a node with some basic properties and driver info
|
|
||||||
- os_ironic:
|
|
||||||
cloud: "devstack"
|
|
||||||
driver: "pxe_ipmitool"
|
|
||||||
uuid: "00000000-0000-0000-0000-000000000002"
|
|
||||||
properties:
|
|
||||||
cpus: 2
|
|
||||||
cpu_arch: "x86_64"
|
|
||||||
ram: 8192
|
|
||||||
disk_size: 64
|
|
||||||
capabilities: "boot_option:local"
|
|
||||||
root_device:
|
|
||||||
wwn: "0x4000cca77fc4dba1"
|
|
||||||
nics:
|
|
||||||
- mac: "aa:bb:cc:aa:bb:cc"
|
|
||||||
- mac: "dd:ee:ff:dd:ee:ff"
|
|
||||||
driver_info:
|
|
||||||
power:
|
|
||||||
ipmi_address: "1.2.3.4"
|
|
||||||
ipmi_username: "admin"
|
|
||||||
ipmi_password: "adminpass"
|
|
||||||
chassis_uuid: "00000000-0000-0000-0000-000000000001"
|
|
||||||
|
|
||||||
'''
|
|
||||||
|
|
||||||
try:
|
|
||||||
import jsonpatch
|
|
||||||
HAS_JSONPATCH = True
|
|
||||||
except ImportError:
|
|
||||||
HAS_JSONPATCH = False
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_properties(module):
|
|
||||||
p = module.params['properties']
|
|
||||||
props = dict(
|
|
||||||
cpu_arch=p.get('cpu_arch') if p.get('cpu_arch') else 'x86_64',
|
|
||||||
cpus=p.get('cpus') if p.get('cpus') else 1,
|
|
||||||
memory_mb=p.get('ram') if p.get('ram') else 1,
|
|
||||||
local_gb=p.get('disk_size') if p.get('disk_size') else 1,
|
|
||||||
capabilities=p.get('capabilities') if p.get('capabilities') else '',
|
|
||||||
root_device=p.get('root_device') if p.get('root_device') else '',
|
|
||||||
)
|
|
||||||
return props
|
|
||||||
|
|
||||||
|
|
||||||
def _parse_driver_info(sdk, module):
|
|
||||||
p = module.params['driver_info']
|
|
||||||
info = p.get('power')
|
|
||||||
if not info:
|
|
||||||
raise sdk.exceptions.OpenStackCloudException(
|
|
||||||
"driver_info['power'] is required")
|
|
||||||
if p.get('console'):
|
|
||||||
info.update(p.get('console'))
|
|
||||||
if p.get('management'):
|
|
||||||
info.update(p.get('management'))
|
|
||||||
if p.get('deploy'):
|
|
||||||
info.update(p.get('deploy'))
|
|
||||||
return info
|
|
||||||
|
|
||||||
|
|
||||||
def _choose_id_value(module):
|
|
||||||
if module.params['uuid']:
|
|
||||||
return module.params['uuid']
|
|
||||||
if module.params['name']:
|
|
||||||
return module.params['name']
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _choose_if_password_only(module, patch):
|
|
||||||
if len(patch) == 1:
|
|
||||||
if 'password' in patch[0]['path'] and module.params['skip_update_of_masked_password']:
|
|
||||||
# Return false to abort update as the password appears
|
|
||||||
# to be the only element in the patch.
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def _exit_node_not_updated(module, server):
|
|
||||||
module.exit_json(
|
|
||||||
changed=False,
|
|
||||||
result="Node not updated",
|
|
||||||
uuid=server['uuid'],
|
|
||||||
provision_state=server['provision_state']
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
uuid=dict(required=False),
|
|
||||||
name=dict(required=False),
|
|
||||||
driver=dict(required=False),
|
|
||||||
driver_info=dict(type='dict', required=True),
|
|
||||||
nics=dict(type='list', required=True, elements="dict"),
|
|
||||||
properties=dict(type='dict', default={}),
|
|
||||||
ironic_url=dict(required=False),
|
|
||||||
chassis_uuid=dict(required=False),
|
|
||||||
skip_update_of_masked_password=dict(
|
|
||||||
required=False,
|
|
||||||
type='bool',
|
|
||||||
aliases=['skip_update_of_driver_password'],
|
|
||||||
deprecated_aliases=[dict(name='skip_update_of_driver_password', version='2.14')]
|
|
||||||
),
|
|
||||||
state=dict(required=False, default='present', choices=['present', 'absent'])
|
|
||||||
)
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
|
|
||||||
if not HAS_JSONPATCH:
|
|
||||||
module.fail_json(msg='jsonpatch is required for this module')
|
|
||||||
if (
|
|
||||||
module.params['auth_type'] in [None, 'None']
|
|
||||||
and module.params['ironic_url'] is None
|
|
||||||
):
|
|
||||||
module.fail_json(msg="Authentication appears to be disabled, "
|
|
||||||
"Please define an ironic_url parameter")
|
|
||||||
|
|
||||||
if (
|
|
||||||
module.params['ironic_url']
|
|
||||||
and module.params['auth_type'] in [None, 'None']
|
|
||||||
):
|
|
||||||
module.params['auth'] = dict(
|
|
||||||
endpoint=module.params['ironic_url']
|
|
||||||
)
|
|
||||||
|
|
||||||
node_id = _choose_id_value(module)
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
server = cloud.get_machine(node_id)
|
|
||||||
if module.params['state'] == 'present':
|
|
||||||
if module.params['driver'] is None:
|
|
||||||
module.fail_json(msg="A driver must be defined in order "
|
|
||||||
"to set a node to present.")
|
|
||||||
|
|
||||||
properties = _parse_properties(module)
|
|
||||||
driver_info = _parse_driver_info(sdk, module)
|
|
||||||
kwargs = dict(
|
|
||||||
driver=module.params['driver'],
|
|
||||||
properties=properties,
|
|
||||||
driver_info=driver_info,
|
|
||||||
name=module.params['name'],
|
|
||||||
)
|
|
||||||
|
|
||||||
if module.params['chassis_uuid']:
|
|
||||||
kwargs['chassis_uuid'] = module.params['chassis_uuid']
|
|
||||||
|
|
||||||
if server is None:
|
|
||||||
# Note(TheJulia): Add a specific UUID to the request if
|
|
||||||
# present in order to be able to re-use kwargs for if
|
|
||||||
# the node already exists logic, since uuid cannot be
|
|
||||||
# updated.
|
|
||||||
if module.params['uuid']:
|
|
||||||
kwargs['uuid'] = module.params['uuid']
|
|
||||||
|
|
||||||
server = cloud.register_machine(module.params['nics'],
|
|
||||||
**kwargs)
|
|
||||||
module.exit_json(changed=True, uuid=server['uuid'],
|
|
||||||
provision_state=server['provision_state'])
|
|
||||||
else:
|
|
||||||
# TODO(TheJulia): Presently this does not support updating
|
|
||||||
# nics. Support needs to be added.
|
|
||||||
#
|
|
||||||
# Note(TheJulia): This message should never get logged
|
|
||||||
# however we cannot realistically proceed if neither a
|
|
||||||
# name or uuid was supplied to begin with.
|
|
||||||
if not node_id:
|
|
||||||
module.fail_json(msg="A uuid or name value "
|
|
||||||
"must be defined")
|
|
||||||
|
|
||||||
# Note(TheJulia): Constructing the configuration to compare
|
|
||||||
# against. The items listed in the server_config block can
|
|
||||||
# be updated via the API.
|
|
||||||
|
|
||||||
server_config = dict(
|
|
||||||
driver=server['driver'],
|
|
||||||
properties=server['properties'],
|
|
||||||
driver_info=server['driver_info'],
|
|
||||||
name=server['name'],
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add the pre-existing chassis_uuid only if
|
|
||||||
# it is present in the server configuration.
|
|
||||||
if hasattr(server, 'chassis_uuid'):
|
|
||||||
server_config['chassis_uuid'] = server['chassis_uuid']
|
|
||||||
|
|
||||||
# Note(TheJulia): If a password is defined and concealed, a
|
|
||||||
# patch will always be generated and re-asserted.
|
|
||||||
patch = jsonpatch.JsonPatch.from_diff(server_config, kwargs)
|
|
||||||
|
|
||||||
if not patch:
|
|
||||||
_exit_node_not_updated(module, server)
|
|
||||||
elif _choose_if_password_only(module, list(patch)):
|
|
||||||
# Note(TheJulia): Normally we would allow the general
|
|
||||||
# exception catch below, however this allows a specific
|
|
||||||
# message.
|
|
||||||
try:
|
|
||||||
server = cloud.patch_machine(
|
|
||||||
server['uuid'],
|
|
||||||
list(patch))
|
|
||||||
except Exception as e:
|
|
||||||
module.fail_json(msg="Failed to update node, "
|
|
||||||
"Error: %s" % e.message)
|
|
||||||
|
|
||||||
# Enumerate out a list of changed paths.
|
|
||||||
change_list = []
|
|
||||||
for change in list(patch):
|
|
||||||
change_list.append(change['path'])
|
|
||||||
module.exit_json(changed=True,
|
|
||||||
result="Node Updated",
|
|
||||||
changes=change_list,
|
|
||||||
uuid=server['uuid'],
|
|
||||||
provision_state=server['provision_state'])
|
|
||||||
|
|
||||||
# Return not updated by default as the conditions were not met
|
|
||||||
# to update.
|
|
||||||
_exit_node_not_updated(module, server)
|
|
||||||
|
|
||||||
if module.params['state'] == 'absent':
|
|
||||||
if not node_id:
|
|
||||||
module.fail_json(msg="A uuid or name value must be defined "
|
|
||||||
"in order to remove a node.")
|
|
||||||
|
|
||||||
if server is not None:
|
|
||||||
cloud.unregister_machine(module.params['nics'],
|
|
||||||
server['uuid'])
|
|
||||||
module.exit_json(changed=True, result="deleted")
|
|
||||||
else:
|
|
||||||
module.exit_json(changed=False, result="Server not found")
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
1
plugins/modules/os_ironic.py
Symbolic link
1
plugins/modules/os_ironic.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
baremetal_node.py
|
@ -1,152 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# coding: utf-8 -*-
|
|
||||||
|
|
||||||
# (c) 2015-2016, Hewlett Packard Enterprise Development Company LP
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_ironic_inspect
|
|
||||||
short_description: Explicitly triggers baremetal node introspection in ironic.
|
|
||||||
author: "Julia Kreger (@juliakreger)"
|
|
||||||
description:
|
|
||||||
- Requests Ironic to set a node into inspect state in order to collect metadata regarding the node.
|
|
||||||
This command may be out of band or in-band depending on the ironic driver configuration.
|
|
||||||
This is only possible on nodes in 'manageable' and 'available' state.
|
|
||||||
options:
|
|
||||||
mac:
|
|
||||||
description:
|
|
||||||
- unique mac address that is used to attempt to identify the host.
|
|
||||||
type: str
|
|
||||||
uuid:
|
|
||||||
description:
|
|
||||||
- globally unique identifier (UUID) to identify the host.
|
|
||||||
type: str
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- unique name identifier to identify the host in Ironic.
|
|
||||||
type: str
|
|
||||||
ironic_url:
|
|
||||||
description:
|
|
||||||
- If noauth mode is utilized, this is required to be set to the endpoint URL for the Ironic API.
|
|
||||||
Use with "auth" and "auth_type" settings set to None.
|
|
||||||
type: str
|
|
||||||
timeout:
|
|
||||||
description:
|
|
||||||
- A timeout in seconds to tell the role to wait for the node to complete introspection if wait is set to True.
|
|
||||||
default: 1200
|
|
||||||
type: int
|
|
||||||
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
ansible_facts:
|
|
||||||
description: Dictionary of new facts representing discovered properties of the node..
|
|
||||||
returned: changed
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
memory_mb:
|
|
||||||
description: Amount of node memory as updated in the node properties
|
|
||||||
type: str
|
|
||||||
sample: "1024"
|
|
||||||
cpu_arch:
|
|
||||||
description: Detected CPU architecture type
|
|
||||||
type: str
|
|
||||||
sample: "x86_64"
|
|
||||||
local_gb:
|
|
||||||
description: Total size of local disk storage as updated in node properties.
|
|
||||||
type: str
|
|
||||||
sample: "10"
|
|
||||||
cpus:
|
|
||||||
description: Count of cpu cores defined in the updated node properties.
|
|
||||||
type: str
|
|
||||||
sample: "1"
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Invoke node inspection
|
|
||||||
- os_ironic_inspect:
|
|
||||||
name: "testnode1"
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _choose_id_value(module):
|
|
||||||
if module.params['uuid']:
|
|
||||||
return module.params['uuid']
|
|
||||||
if module.params['name']:
|
|
||||||
return module.params['name']
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
auth_type=dict(required=False),
|
|
||||||
uuid=dict(required=False),
|
|
||||||
name=dict(required=False),
|
|
||||||
mac=dict(required=False),
|
|
||||||
ironic_url=dict(required=False),
|
|
||||||
timeout=dict(default=1200, type='int', required=False),
|
|
||||||
)
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
|
|
||||||
if (
|
|
||||||
module.params['auth_type'] in [None, 'None']
|
|
||||||
and module.params['ironic_url'] is None
|
|
||||||
):
|
|
||||||
module.fail_json(msg="Authentication appears to be disabled, "
|
|
||||||
"Please define an ironic_url parameter")
|
|
||||||
|
|
||||||
if (
|
|
||||||
module.params['ironic_url']
|
|
||||||
and module.params['auth_type'] in [None, 'None']
|
|
||||||
):
|
|
||||||
module.params['auth'] = dict(
|
|
||||||
endpoint=module.params['ironic_url']
|
|
||||||
)
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
if module.params['name'] or module.params['uuid']:
|
|
||||||
server = cloud.get_machine(_choose_id_value(module))
|
|
||||||
elif module.params['mac']:
|
|
||||||
server = cloud.get_machine_by_mac(module.params['mac'])
|
|
||||||
else:
|
|
||||||
module.fail_json(msg="The worlds did not align, "
|
|
||||||
"the host was not found as "
|
|
||||||
"no name, uuid, or mac was "
|
|
||||||
"defined.")
|
|
||||||
if server:
|
|
||||||
cloud.inspect_machine(server['uuid'], module.params['wait'])
|
|
||||||
# TODO(TheJulia): diff properties, ?and ports? and determine
|
|
||||||
# if a change occurred. In theory, the node is always changed
|
|
||||||
# if introspection is able to update the record.
|
|
||||||
module.exit_json(changed=True,
|
|
||||||
ansible_facts=server['properties'])
|
|
||||||
|
|
||||||
else:
|
|
||||||
module.fail_json(msg="node not found.")
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
1
plugins/modules/os_ironic_inspect.py
Symbolic link
1
plugins/modules/os_ironic_inspect.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
baremetal_inspect.py
|
@ -1,379 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# coding: utf-8 -*-
|
|
||||||
|
|
||||||
# (c) 2015, Hewlett-Packard Development Company, L.P.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_ironic_node
|
|
||||||
short_description: Activate/Deactivate Bare Metal Resources from OpenStack
|
|
||||||
author: "Monty Taylor (@emonty)"
|
|
||||||
description:
|
|
||||||
- Deploy to nodes controlled by Ironic.
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name of the node to create.
|
|
||||||
type: str
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Indicates desired state of the resource.
|
|
||||||
- I(state) can be C('present'), C('absent'), C('maintenance') or C('off').
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
deploy:
|
|
||||||
description:
|
|
||||||
- Indicates if the resource should be deployed. Allows for deployment
|
|
||||||
logic to be disengaged and control of the node power or maintenance
|
|
||||||
state to be changed.
|
|
||||||
type: str
|
|
||||||
default: 'yes'
|
|
||||||
uuid:
|
|
||||||
description:
|
|
||||||
- globally unique identifier (UUID) to be given to the resource.
|
|
||||||
type: str
|
|
||||||
ironic_url:
|
|
||||||
description:
|
|
||||||
- If noauth mode is utilized, this is required to be set to the
|
|
||||||
endpoint URL for the Ironic API. Use with "auth" and "auth_type"
|
|
||||||
settings set to None.
|
|
||||||
type: str
|
|
||||||
config_drive:
|
|
||||||
description:
|
|
||||||
- A configdrive file or HTTP(S) URL that will be passed along to the
|
|
||||||
node.
|
|
||||||
type: raw
|
|
||||||
instance_info:
|
|
||||||
description:
|
|
||||||
- Definition of the instance information which is used to deploy
|
|
||||||
the node. This information is only required when an instance is
|
|
||||||
set to present.
|
|
||||||
type: dict
|
|
||||||
suboptions:
|
|
||||||
image_source:
|
|
||||||
description:
|
|
||||||
- An HTTP(S) URL where the image can be retrieved from.
|
|
||||||
image_checksum:
|
|
||||||
description:
|
|
||||||
- The checksum of image_source.
|
|
||||||
image_disk_format:
|
|
||||||
description:
|
|
||||||
- The type of image that has been requested to be deployed.
|
|
||||||
power:
|
|
||||||
description:
|
|
||||||
- A setting to allow power state to be asserted allowing nodes
|
|
||||||
that are not yet deployed to be powered on, and nodes that
|
|
||||||
are deployed to be powered off.
|
|
||||||
- I(power) can be C('present'), C('absent'), C('maintenance') or C('off').
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
maintenance:
|
|
||||||
description:
|
|
||||||
- A setting to allow the direct control if a node is in
|
|
||||||
maintenance mode.
|
|
||||||
- I(maintenance) can be C('yes'), C('no'), C('True'), or C('False').
|
|
||||||
type: str
|
|
||||||
maintenance_reason:
|
|
||||||
description:
|
|
||||||
- A string expression regarding the reason a node is in a
|
|
||||||
maintenance mode.
|
|
||||||
type: str
|
|
||||||
wait:
|
|
||||||
description:
|
|
||||||
- A boolean value instructing the module to wait for node
|
|
||||||
activation or deactivation to complete before returning.
|
|
||||||
type: bool
|
|
||||||
default: 'no'
|
|
||||||
timeout:
|
|
||||||
description:
|
|
||||||
- An integer value representing the number of seconds to
|
|
||||||
wait for the node activation or deactivation to complete.
|
|
||||||
default: 1800
|
|
||||||
type: int
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Activate a node by booting an image with a configdrive attached
|
|
||||||
- os_ironic_node:
|
|
||||||
cloud: "openstack"
|
|
||||||
uuid: "d44666e1-35b3-4f6b-acb0-88ab7052da69"
|
|
||||||
state: present
|
|
||||||
power: present
|
|
||||||
deploy: True
|
|
||||||
maintenance: False
|
|
||||||
config_drive: "http://192.168.1.1/host-configdrive.iso"
|
|
||||||
instance_info:
|
|
||||||
image_source: "http://192.168.1.1/deploy_image.img"
|
|
||||||
image_checksum: "356a6b55ecc511a20c33c946c4e678af"
|
|
||||||
image_disk_format: "qcow"
|
|
||||||
delegate_to: localhost
|
|
||||||
|
|
||||||
# Activate a node by booting an image with a configdrive json object
|
|
||||||
- os_ironic_node:
|
|
||||||
uuid: "d44666e1-35b3-4f6b-acb0-88ab7052da69"
|
|
||||||
auth_type: None
|
|
||||||
ironic_url: "http://192.168.1.1:6385/"
|
|
||||||
config_drive:
|
|
||||||
meta_data:
|
|
||||||
hostname: node1
|
|
||||||
public_keys:
|
|
||||||
default: ssh-rsa AAA...BBB==
|
|
||||||
instance_info:
|
|
||||||
image_source: "http://192.168.1.1/deploy_image.img"
|
|
||||||
image_checksum: "356a6b55ecc511a20c33c946c4e678af"
|
|
||||||
image_disk_format: "qcow"
|
|
||||||
delegate_to: localhost
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _choose_id_value(module):
|
|
||||||
if module.params['uuid']:
|
|
||||||
return module.params['uuid']
|
|
||||||
if module.params['name']:
|
|
||||||
return module.params['name']
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def _is_true(value):
|
|
||||||
true_values = [True, 'yes', 'Yes', 'True', 'true', 'present', 'on']
|
|
||||||
if value in true_values:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _is_false(value):
|
|
||||||
false_values = [False, None, 'no', 'No', 'False', 'false', 'absent', 'off']
|
|
||||||
if value in false_values:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _check_set_maintenance(module, cloud, node):
|
|
||||||
if _is_true(module.params['maintenance']):
|
|
||||||
if _is_false(node['maintenance']):
|
|
||||||
cloud.set_machine_maintenance_state(
|
|
||||||
node['uuid'],
|
|
||||||
True,
|
|
||||||
reason=module.params['maintenance_reason'])
|
|
||||||
module.exit_json(changed=True, msg="Node has been set into "
|
|
||||||
"maintenance mode")
|
|
||||||
else:
|
|
||||||
# User has requested maintenance state, node is already in the
|
|
||||||
# desired state, checking to see if the reason has changed.
|
|
||||||
if (str(node['maintenance_reason']) not in
|
|
||||||
str(module.params['maintenance_reason'])):
|
|
||||||
cloud.set_machine_maintenance_state(
|
|
||||||
node['uuid'],
|
|
||||||
True,
|
|
||||||
reason=module.params['maintenance_reason'])
|
|
||||||
module.exit_json(changed=True, msg="Node maintenance reason "
|
|
||||||
"updated, cannot take any "
|
|
||||||
"additional action.")
|
|
||||||
elif _is_false(module.params['maintenance']):
|
|
||||||
if node['maintenance'] is True:
|
|
||||||
cloud.remove_machine_from_maintenance(node['uuid'])
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
module.fail_json(msg="maintenance parameter was set but a valid "
|
|
||||||
"the value was not recognized.")
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _check_set_power_state(module, cloud, node):
|
|
||||||
if 'power on' in str(node['power_state']):
|
|
||||||
if _is_false(module.params['power']):
|
|
||||||
# User has requested the node be powered off.
|
|
||||||
cloud.set_machine_power_off(node['uuid'])
|
|
||||||
module.exit_json(changed=True, msg="Power requested off")
|
|
||||||
if 'power off' in str(node['power_state']):
|
|
||||||
if (
|
|
||||||
_is_false(module.params['power'])
|
|
||||||
and _is_false(module.params['state'])
|
|
||||||
):
|
|
||||||
return False
|
|
||||||
if (
|
|
||||||
_is_false(module.params['power'])
|
|
||||||
and _is_false(module.params['state'])
|
|
||||||
):
|
|
||||||
module.exit_json(
|
|
||||||
changed=False,
|
|
||||||
msg="Power for node is %s, node must be reactivated "
|
|
||||||
"OR set to state absent"
|
|
||||||
)
|
|
||||||
# In the event the power has been toggled on and
|
|
||||||
# deployment has been requested, we need to skip this
|
|
||||||
# step.
|
|
||||||
if (
|
|
||||||
_is_true(module.params['power'])
|
|
||||||
and _is_false(module.params['deploy'])
|
|
||||||
):
|
|
||||||
# Node is powered down when it is not awaiting to be provisioned
|
|
||||||
cloud.set_machine_power_on(node['uuid'])
|
|
||||||
return True
|
|
||||||
# Default False if no action has been taken.
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
uuid=dict(required=False),
|
|
||||||
name=dict(required=False),
|
|
||||||
instance_info=dict(type='dict', required=False),
|
|
||||||
config_drive=dict(type='raw', required=False),
|
|
||||||
ironic_url=dict(required=False),
|
|
||||||
state=dict(required=False, default='present'),
|
|
||||||
maintenance=dict(required=False),
|
|
||||||
maintenance_reason=dict(required=False),
|
|
||||||
power=dict(required=False, default='present'),
|
|
||||||
deploy=dict(required=False, default='yes'),
|
|
||||||
wait=dict(type='bool', required=False, default=False),
|
|
||||||
timeout=dict(required=False, type='int', default=1800),
|
|
||||||
)
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
|
|
||||||
if (
|
|
||||||
module.params['auth_type'] in [None, 'None']
|
|
||||||
and module.params['ironic_url'] is None
|
|
||||||
):
|
|
||||||
module.fail_json(msg="Authentication appears disabled, Please "
|
|
||||||
"define an ironic_url parameter")
|
|
||||||
|
|
||||||
if (
|
|
||||||
module.params['ironic_url']
|
|
||||||
and module.params['auth_type'] in [None, 'None']
|
|
||||||
):
|
|
||||||
module.params['auth'] = dict(
|
|
||||||
endpoint=module.params['ironic_url']
|
|
||||||
)
|
|
||||||
|
|
||||||
if (
|
|
||||||
module.params['config_drive']
|
|
||||||
and not isinstance(module.params['config_drive'], (str, dict))
|
|
||||||
):
|
|
||||||
config_drive_type = type(module.params['config_drive'])
|
|
||||||
msg = ('argument config_drive is of type %s and we expected'
|
|
||||||
' str or dict') % config_drive_type
|
|
||||||
module.fail_json(msg=msg)
|
|
||||||
|
|
||||||
node_id = _choose_id_value(module)
|
|
||||||
|
|
||||||
if not node_id:
|
|
||||||
module.fail_json(msg="A uuid or name value must be defined "
|
|
||||||
"to use this module.")
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
node = cloud.get_machine(node_id)
|
|
||||||
|
|
||||||
if node is None:
|
|
||||||
module.fail_json(msg="node not found")
|
|
||||||
|
|
||||||
uuid = node['uuid']
|
|
||||||
instance_info = module.params['instance_info']
|
|
||||||
changed = False
|
|
||||||
wait = module.params['wait']
|
|
||||||
timeout = module.params['timeout']
|
|
||||||
|
|
||||||
# User has requested desired state to be in maintenance state.
|
|
||||||
if module.params['state'] == 'maintenance':
|
|
||||||
module.params['maintenance'] = True
|
|
||||||
|
|
||||||
if node['provision_state'] in [
|
|
||||||
'cleaning',
|
|
||||||
'deleting',
|
|
||||||
'wait call-back']:
|
|
||||||
module.fail_json(msg="Node is in %s state, cannot act upon the "
|
|
||||||
"request as the node is in a transition "
|
|
||||||
"state" % node['provision_state'])
|
|
||||||
# TODO(TheJulia) This is in-development code, that requires
|
|
||||||
# code in the shade library that is still in development.
|
|
||||||
if _check_set_maintenance(module, cloud, node):
|
|
||||||
if node['provision_state'] in 'active':
|
|
||||||
module.exit_json(changed=True,
|
|
||||||
result="Maintenance state changed")
|
|
||||||
changed = True
|
|
||||||
node = cloud.get_machine(node_id)
|
|
||||||
|
|
||||||
if _check_set_power_state(module, cloud, node):
|
|
||||||
changed = True
|
|
||||||
node = cloud.get_machine(node_id)
|
|
||||||
|
|
||||||
if _is_true(module.params['state']):
|
|
||||||
if _is_false(module.params['deploy']):
|
|
||||||
module.exit_json(
|
|
||||||
changed=changed,
|
|
||||||
result="User request has explicitly disabled "
|
|
||||||
"deployment logic"
|
|
||||||
)
|
|
||||||
|
|
||||||
if 'active' in node['provision_state']:
|
|
||||||
module.exit_json(
|
|
||||||
changed=changed,
|
|
||||||
result="Node already in an active state."
|
|
||||||
)
|
|
||||||
|
|
||||||
if instance_info is None:
|
|
||||||
module.fail_json(
|
|
||||||
changed=changed,
|
|
||||||
msg="When setting an instance to present, "
|
|
||||||
"instance_info is a required variable.")
|
|
||||||
|
|
||||||
# TODO(TheJulia): Update instance info, however info is
|
|
||||||
# deployment specific. Perhaps consider adding rebuild
|
|
||||||
# support, although there is a known desire to remove
|
|
||||||
# rebuild support from Ironic at some point in the future.
|
|
||||||
cloud.update_machine(uuid, instance_info=instance_info)
|
|
||||||
cloud.validate_node(uuid)
|
|
||||||
if not wait:
|
|
||||||
cloud.activate_node(uuid, module.params['config_drive'])
|
|
||||||
else:
|
|
||||||
cloud.activate_node(
|
|
||||||
uuid,
|
|
||||||
configdrive=module.params['config_drive'],
|
|
||||||
wait=wait,
|
|
||||||
timeout=timeout)
|
|
||||||
# TODO(TheJulia): Add more error checking..
|
|
||||||
module.exit_json(changed=changed, result="node activated")
|
|
||||||
|
|
||||||
elif _is_false(module.params['state']):
|
|
||||||
if node['provision_state'] not in "deleted":
|
|
||||||
cloud.update_machine(uuid, instance_info={})
|
|
||||||
if not wait:
|
|
||||||
cloud.deactivate_node(uuid)
|
|
||||||
else:
|
|
||||||
cloud.deactivate_node(
|
|
||||||
uuid,
|
|
||||||
wait=wait,
|
|
||||||
timeout=timeout)
|
|
||||||
|
|
||||||
module.exit_json(changed=True, result="deleted")
|
|
||||||
else:
|
|
||||||
module.exit_json(changed=False, result="node not found")
|
|
||||||
else:
|
|
||||||
module.fail_json(msg="State must be present, absent, "
|
|
||||||
"maintenance, off")
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
1
plugins/modules/os_ironic_node.py
Symbolic link
1
plugins/modules/os_ironic_node.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
baremetal_node_action.py
|
@ -1,167 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
|
|
||||||
# Copyright (c) 2013, Benno Joy <benno@ansible.com>
|
|
||||||
# Copyright (c) 2013, John Dewey <john@dewey.ws>
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_keypair
|
|
||||||
short_description: Add/Delete a keypair from OpenStack
|
|
||||||
author: "Benno Joy (@bennojoy)"
|
|
||||||
description:
|
|
||||||
- Add or Remove key pair from OpenStack
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name that has to be given to the key pair
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
public_key:
|
|
||||||
description:
|
|
||||||
- The public key that would be uploaded to nova and injected into VMs
|
|
||||||
upon creation.
|
|
||||||
type: str
|
|
||||||
public_key_file:
|
|
||||||
description:
|
|
||||||
- Path to local file containing ssh public key. Mutually exclusive
|
|
||||||
with public_key.
|
|
||||||
type: str
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Should the resource be present or absent. If state is replace and
|
|
||||||
the key exists but has different content, delete it and recreate it
|
|
||||||
with the new content.
|
|
||||||
choices: [present, absent, replace]
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Creates a key pair with the running users public key
|
|
||||||
- os_keypair:
|
|
||||||
cloud: mordred
|
|
||||||
state: present
|
|
||||||
name: ansible_key
|
|
||||||
public_key_file: /home/me/.ssh/id_rsa.pub
|
|
||||||
|
|
||||||
# Creates a new key pair and the private key returned after the run.
|
|
||||||
- os_keypair:
|
|
||||||
cloud: rax-dfw
|
|
||||||
state: present
|
|
||||||
name: ansible_key
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
id:
|
|
||||||
description: Unique UUID.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
name:
|
|
||||||
description: Name given to the keypair.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
public_key:
|
|
||||||
description: The public key value for the keypair.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
private_key:
|
|
||||||
description: The private key value for the keypair.
|
|
||||||
returned: Only when a keypair is generated for the user (e.g., when creating one
|
|
||||||
and a public key is not specified).
|
|
||||||
type: str
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _system_state_change(module, keypair):
|
|
||||||
state = module.params['state']
|
|
||||||
if state == 'present' and not keypair:
|
|
||||||
return True
|
|
||||||
if state == 'absent' and keypair:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
name=dict(required=True),
|
|
||||||
public_key=dict(default=None),
|
|
||||||
public_key_file=dict(default=None),
|
|
||||||
state=dict(default='present',
|
|
||||||
choices=['absent', 'present', 'replace']),
|
|
||||||
)
|
|
||||||
|
|
||||||
module_kwargs = openstack_module_kwargs(
|
|
||||||
mutually_exclusive=[['public_key', 'public_key_file']])
|
|
||||||
|
|
||||||
module = AnsibleModule(argument_spec,
|
|
||||||
supports_check_mode=True,
|
|
||||||
**module_kwargs)
|
|
||||||
|
|
||||||
state = module.params['state']
|
|
||||||
name = module.params['name']
|
|
||||||
public_key = module.params['public_key']
|
|
||||||
|
|
||||||
if module.params['public_key_file']:
|
|
||||||
with open(module.params['public_key_file']) as public_key_fh:
|
|
||||||
public_key = public_key_fh.read().rstrip()
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
keypair = cloud.get_keypair(name)
|
|
||||||
|
|
||||||
if module.check_mode:
|
|
||||||
module.exit_json(changed=_system_state_change(module, keypair))
|
|
||||||
|
|
||||||
if state in ('present', 'replace'):
|
|
||||||
if keypair and keypair['name'] == name:
|
|
||||||
if public_key and (public_key != keypair['public_key']):
|
|
||||||
if state == 'present':
|
|
||||||
module.fail_json(
|
|
||||||
msg="Key name %s present but key hash not the same"
|
|
||||||
" as offered. Delete key first." % name
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
cloud.delete_keypair(name)
|
|
||||||
keypair = cloud.create_keypair(name, public_key)
|
|
||||||
changed = True
|
|
||||||
else:
|
|
||||||
changed = False
|
|
||||||
else:
|
|
||||||
keypair = cloud.create_keypair(name, public_key)
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
module.exit_json(changed=changed,
|
|
||||||
key=keypair,
|
|
||||||
id=keypair['id'])
|
|
||||||
|
|
||||||
elif state == 'absent':
|
|
||||||
if keypair:
|
|
||||||
cloud.delete_keypair(name)
|
|
||||||
module.exit_json(changed=True)
|
|
||||||
module.exit_json(changed=False)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_keypair.py
Symbolic link
1
plugins/modules/os_keypair.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
keypair.py
|
@ -1,185 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# Copyright (c) 2015 Hewlett-Packard Development Company, L.P.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_keystone_domain
|
|
||||||
short_description: Manage OpenStack Identity Domains
|
|
||||||
author:
|
|
||||||
- Monty Taylor (@emonty)
|
|
||||||
- Haneef Ali (@haneefs)
|
|
||||||
description:
|
|
||||||
- Create, update, or delete OpenStack Identity domains. If a domain
|
|
||||||
with the supplied name already exists, it will be updated with the
|
|
||||||
new description and enabled attributes.
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name that has to be given to the instance
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
description:
|
|
||||||
- Description of the domain
|
|
||||||
type: str
|
|
||||||
enabled:
|
|
||||||
description:
|
|
||||||
- Is the domain enabled
|
|
||||||
type: bool
|
|
||||||
default: 'yes'
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Should the resource be present or absent.
|
|
||||||
choices: [present, absent]
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Create a domain
|
|
||||||
- os_keystone_domain:
|
|
||||||
cloud: mycloud
|
|
||||||
state: present
|
|
||||||
name: demo
|
|
||||||
description: Demo Domain
|
|
||||||
|
|
||||||
# Delete a domain
|
|
||||||
- os_keystone_domain:
|
|
||||||
cloud: mycloud
|
|
||||||
state: absent
|
|
||||||
name: demo
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
domain:
|
|
||||||
description: Dictionary describing the domain.
|
|
||||||
returned: On success when I(state) is 'present'
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
id:
|
|
||||||
description: Domain ID.
|
|
||||||
type: str
|
|
||||||
sample: "474acfe5-be34-494c-b339-50f06aa143e4"
|
|
||||||
name:
|
|
||||||
description: Domain name.
|
|
||||||
type: str
|
|
||||||
sample: "demo"
|
|
||||||
description:
|
|
||||||
description: Domain description.
|
|
||||||
type: str
|
|
||||||
sample: "Demo Domain"
|
|
||||||
enabled:
|
|
||||||
description: Domain description.
|
|
||||||
type: bool
|
|
||||||
sample: True
|
|
||||||
|
|
||||||
id:
|
|
||||||
description: The domain ID.
|
|
||||||
returned: On success when I(state) is 'present'
|
|
||||||
type: str
|
|
||||||
sample: "474acfe5-be34-494c-b339-50f06aa143e4"
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _needs_update(module, domain):
|
|
||||||
if module.params['description'] is not None and \
|
|
||||||
domain.description != module.params['description']:
|
|
||||||
return True
|
|
||||||
if domain.enabled != module.params['enabled']:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _system_state_change(module, domain):
|
|
||||||
state = module.params['state']
|
|
||||||
if state == 'absent' and domain:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if state == 'present':
|
|
||||||
if domain is None:
|
|
||||||
return True
|
|
||||||
return _needs_update(module, domain)
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
name=dict(required=True),
|
|
||||||
description=dict(default=None),
|
|
||||||
enabled=dict(default=True, type='bool'),
|
|
||||||
state=dict(default='present', choices=['absent', 'present']),
|
|
||||||
)
|
|
||||||
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec,
|
|
||||||
supports_check_mode=True,
|
|
||||||
**module_kwargs)
|
|
||||||
|
|
||||||
name = module.params['name']
|
|
||||||
description = module.params['description']
|
|
||||||
enabled = module.params['enabled']
|
|
||||||
state = module.params['state']
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
|
|
||||||
domains = cloud.search_domains(filters=dict(name=name))
|
|
||||||
|
|
||||||
if len(domains) > 1:
|
|
||||||
module.fail_json(msg='Domain name %s is not unique' % name)
|
|
||||||
elif len(domains) == 1:
|
|
||||||
domain = domains[0]
|
|
||||||
else:
|
|
||||||
domain = None
|
|
||||||
|
|
||||||
if module.check_mode:
|
|
||||||
module.exit_json(changed=_system_state_change(module, domain))
|
|
||||||
|
|
||||||
if state == 'present':
|
|
||||||
if domain is None:
|
|
||||||
domain = cloud.create_domain(
|
|
||||||
name=name, description=description, enabled=enabled)
|
|
||||||
changed = True
|
|
||||||
else:
|
|
||||||
if _needs_update(module, domain):
|
|
||||||
domain = cloud.update_domain(
|
|
||||||
domain.id, name=name, description=description,
|
|
||||||
enabled=enabled)
|
|
||||||
changed = True
|
|
||||||
else:
|
|
||||||
changed = False
|
|
||||||
module.exit_json(changed=changed, domain=domain, id=domain.id)
|
|
||||||
|
|
||||||
elif state == 'absent':
|
|
||||||
if domain is None:
|
|
||||||
changed = False
|
|
||||||
else:
|
|
||||||
cloud.delete_domain(domain.id)
|
|
||||||
changed = True
|
|
||||||
module.exit_json(changed=changed)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_keystone_domain.py
Symbolic link
1
plugins/modules/os_keystone_domain.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
identity_domain.py
|
@ -1,139 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# Copyright (c) 2016 Hewlett-Packard Enterprise Corporation
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_keystone_domain_info
|
|
||||||
short_description: Retrieve information about one or more OpenStack domains
|
|
||||||
author: "Ricardo Carrillo Cruz (@rcarrillocruz)"
|
|
||||||
description:
|
|
||||||
- Retrieve information about a one or more OpenStack domains
|
|
||||||
- This module was called C(os_keystone_domain_facts) before Ansible 2.9, returning C(ansible_facts).
|
|
||||||
Note that the M(os_keystone_domain_info) module no longer returns C(ansible_facts)!
|
|
||||||
options:
|
|
||||||
name:
|
|
||||||
description:
|
|
||||||
- Name or ID of the domain
|
|
||||||
type: str
|
|
||||||
filters:
|
|
||||||
description:
|
|
||||||
- A dictionary of meta data to use for further filtering. Elements of
|
|
||||||
this dictionary may be additional dictionaries.
|
|
||||||
type: dict
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
# Gather information about previously created domain
|
|
||||||
- os_keystone_domain_info:
|
|
||||||
cloud: awesomecloud
|
|
||||||
register: result
|
|
||||||
- debug:
|
|
||||||
msg: "{{ result.openstack_domains }}"
|
|
||||||
|
|
||||||
# Gather information about a previously created domain by name
|
|
||||||
- os_keystone_domain_info:
|
|
||||||
cloud: awesomecloud
|
|
||||||
name: demodomain
|
|
||||||
register: result
|
|
||||||
- debug:
|
|
||||||
msg: "{{ result.openstack_domains }}"
|
|
||||||
|
|
||||||
# Gather information about a previously created domain with filter
|
|
||||||
- os_keystone_domain_info:
|
|
||||||
cloud: awesomecloud
|
|
||||||
name: demodomain
|
|
||||||
filters:
|
|
||||||
enabled: false
|
|
||||||
register: result
|
|
||||||
- debug:
|
|
||||||
msg: "{{ result.openstack_domains }}"
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
openstack_domains:
|
|
||||||
description: has all the OpenStack information about domains
|
|
||||||
returned: always, but can be null
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
id:
|
|
||||||
description: Unique UUID.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
name:
|
|
||||||
description: Name given to the domain.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
description:
|
|
||||||
description: Description of the domain.
|
|
||||||
returned: success
|
|
||||||
type: str
|
|
||||||
enabled:
|
|
||||||
description: Flag to indicate if the domain is enabled.
|
|
||||||
returned: success
|
|
||||||
type: bool
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
name=dict(required=False, default=None),
|
|
||||||
filters=dict(required=False, type='dict', default=None),
|
|
||||||
)
|
|
||||||
module_kwargs = openstack_module_kwargs(
|
|
||||||
mutually_exclusive=[
|
|
||||||
['name', 'filters'],
|
|
||||||
]
|
|
||||||
)
|
|
||||||
module = AnsibleModule(argument_spec, **module_kwargs)
|
|
||||||
is_old_facts = module._name == 'os_keystone_domain_facts'
|
|
||||||
if is_old_facts:
|
|
||||||
module.deprecate("The 'os_keystone_domain_facts' module has been renamed to 'os_keystone_domain_info', "
|
|
||||||
"and the renamed one no longer returns ansible_facts", version='2.13')
|
|
||||||
|
|
||||||
sdk, opcloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
name = module.params['name']
|
|
||||||
filters = module.params['filters']
|
|
||||||
|
|
||||||
if name:
|
|
||||||
# Let's suppose user is passing domain ID
|
|
||||||
try:
|
|
||||||
domains = opcloud.get_domain(name)
|
|
||||||
except Exception:
|
|
||||||
domains = opcloud.search_domains(filters={'name': name})
|
|
||||||
|
|
||||||
else:
|
|
||||||
domains = opcloud.search_domains(filters)
|
|
||||||
|
|
||||||
if is_old_facts:
|
|
||||||
module.exit_json(changed=False, ansible_facts=dict(
|
|
||||||
openstack_domains=domains))
|
|
||||||
else:
|
|
||||||
module.exit_json(changed=False, openstack_domains=domains)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_keystone_domain_info.py
Symbolic link
1
plugins/modules/os_keystone_domain_info.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
identity_domain_info.py
|
@ -1,215 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
# Copyright: (c) 2017, VEXXHOST, Inc.
|
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
|
||||||
|
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|
||||||
'status': ['preview'],
|
|
||||||
'supported_by': 'community'}
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
|
||||||
---
|
|
||||||
module: os_keystone_endpoint
|
|
||||||
short_description: Manage OpenStack Identity service endpoints
|
|
||||||
author:
|
|
||||||
- Mohammed Naser (@mnaser)
|
|
||||||
- Alberto Murillo (@albertomurillo)
|
|
||||||
description:
|
|
||||||
- Create, update, or delete OpenStack Identity service endpoints. If a
|
|
||||||
service with the same combination of I(service), I(interface) and I(region)
|
|
||||||
exist, the I(url) and I(state) (C(present) or C(absent)) will be updated.
|
|
||||||
options:
|
|
||||||
service:
|
|
||||||
description:
|
|
||||||
- Name or id of the service.
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
endpoint_interface:
|
|
||||||
description:
|
|
||||||
- Interface of the service.
|
|
||||||
choices: [admin, public, internal]
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
url:
|
|
||||||
description:
|
|
||||||
- URL of the service.
|
|
||||||
required: true
|
|
||||||
type: str
|
|
||||||
region:
|
|
||||||
description:
|
|
||||||
- Region that the service belongs to. Note that I(region_name) is used for authentication.
|
|
||||||
type: str
|
|
||||||
enabled:
|
|
||||||
description:
|
|
||||||
- Is the service enabled.
|
|
||||||
default: True
|
|
||||||
type: bool
|
|
||||||
state:
|
|
||||||
description:
|
|
||||||
- Should the resource be C(present) or C(absent).
|
|
||||||
choices: [present, absent]
|
|
||||||
default: present
|
|
||||||
type: str
|
|
||||||
requirements:
|
|
||||||
- "python >= 3.6"
|
|
||||||
- "openstacksdk >= 0.13.0"
|
|
||||||
|
|
||||||
extends_documentation_fragment:
|
|
||||||
- openstack.cloud.openstack
|
|
||||||
'''
|
|
||||||
|
|
||||||
EXAMPLES = '''
|
|
||||||
- name: Create a service for glance
|
|
||||||
os_keystone_endpoint:
|
|
||||||
cloud: mycloud
|
|
||||||
service: glance
|
|
||||||
endpoint_interface: public
|
|
||||||
url: http://controller:9292
|
|
||||||
region: RegionOne
|
|
||||||
state: present
|
|
||||||
|
|
||||||
- name: Delete a service for nova
|
|
||||||
os_keystone_endpoint:
|
|
||||||
cloud: mycloud
|
|
||||||
service: nova
|
|
||||||
endpoint_interface: public
|
|
||||||
region: RegionOne
|
|
||||||
state: absent
|
|
||||||
'''
|
|
||||||
|
|
||||||
RETURN = '''
|
|
||||||
endpoint:
|
|
||||||
description: Dictionary describing the endpoint.
|
|
||||||
returned: On success when I(state) is C(present)
|
|
||||||
type: complex
|
|
||||||
contains:
|
|
||||||
id:
|
|
||||||
description: Endpoint ID.
|
|
||||||
type: str
|
|
||||||
sample: 3292f020780b4d5baf27ff7e1d224c44
|
|
||||||
region:
|
|
||||||
description: Region Name.
|
|
||||||
type: str
|
|
||||||
sample: RegionOne
|
|
||||||
service_id:
|
|
||||||
description: Service ID.
|
|
||||||
type: str
|
|
||||||
sample: b91f1318f735494a825a55388ee118f3
|
|
||||||
interface:
|
|
||||||
description: Endpoint Interface.
|
|
||||||
type: str
|
|
||||||
sample: public
|
|
||||||
url:
|
|
||||||
description: Service URL.
|
|
||||||
type: str
|
|
||||||
sample: http://controller:9292
|
|
||||||
enabled:
|
|
||||||
description: Service status.
|
|
||||||
type: bool
|
|
||||||
sample: True
|
|
||||||
'''
|
|
||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
|
||||||
from ansible_collections.openstack.cloud.plugins.module_utils.openstack import (openstack_full_argument_spec,
|
|
||||||
openstack_module_kwargs,
|
|
||||||
openstack_cloud_from_module)
|
|
||||||
|
|
||||||
|
|
||||||
def _needs_update(module, endpoint):
|
|
||||||
if endpoint.enabled != module.params['enabled']:
|
|
||||||
return True
|
|
||||||
if endpoint.url != module.params['url']:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _system_state_change(module, endpoint):
|
|
||||||
state = module.params['state']
|
|
||||||
if state == 'absent' and endpoint:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if state == 'present':
|
|
||||||
if endpoint is None:
|
|
||||||
return True
|
|
||||||
return _needs_update(module, endpoint)
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
argument_spec = openstack_full_argument_spec(
|
|
||||||
service=dict(type='str', required=True),
|
|
||||||
endpoint_interface=dict(type='str', required=True, choices=['admin', 'public', 'internal']),
|
|
||||||
url=dict(type='str', required=True),
|
|
||||||
region=dict(type='str'),
|
|
||||||
enabled=dict(type='bool', default=True),
|
|
||||||
state=dict(type='str', default='present', choices=['absent', 'present']),
|
|
||||||
)
|
|
||||||
|
|
||||||
module_kwargs = openstack_module_kwargs()
|
|
||||||
module = AnsibleModule(argument_spec,
|
|
||||||
supports_check_mode=True,
|
|
||||||
**module_kwargs)
|
|
||||||
|
|
||||||
service_name_or_id = module.params['service']
|
|
||||||
interface = module.params['endpoint_interface']
|
|
||||||
url = module.params['url']
|
|
||||||
region = module.params['region']
|
|
||||||
enabled = module.params['enabled']
|
|
||||||
state = module.params['state']
|
|
||||||
|
|
||||||
sdk, cloud = openstack_cloud_from_module(module)
|
|
||||||
try:
|
|
||||||
|
|
||||||
service = cloud.get_service(service_name_or_id)
|
|
||||||
if service is None:
|
|
||||||
module.fail_json(msg='Service %s does not exist' % service_name_or_id)
|
|
||||||
|
|
||||||
filters = dict(service_id=service.id, interface=interface)
|
|
||||||
if region is not None:
|
|
||||||
filters['region'] = region
|
|
||||||
endpoints = cloud.search_endpoints(filters=filters)
|
|
||||||
|
|
||||||
if len(endpoints) > 1:
|
|
||||||
module.fail_json(msg='Service %s, interface %s and region %s are '
|
|
||||||
'not unique' %
|
|
||||||
(service_name_or_id, interface, region))
|
|
||||||
elif len(endpoints) == 1:
|
|
||||||
endpoint = endpoints[0]
|
|
||||||
else:
|
|
||||||
endpoint = None
|
|
||||||
|
|
||||||
if module.check_mode:
|
|
||||||
module.exit_json(changed=_system_state_change(module, endpoint))
|
|
||||||
|
|
||||||
if state == 'present':
|
|
||||||
if endpoint is None:
|
|
||||||
result = cloud.create_endpoint(service_name_or_id=service,
|
|
||||||
url=url, interface=interface,
|
|
||||||
region=region, enabled=enabled)
|
|
||||||
endpoint = result[0]
|
|
||||||
changed = True
|
|
||||||
else:
|
|
||||||
if _needs_update(module, endpoint):
|
|
||||||
endpoint = cloud.update_endpoint(
|
|
||||||
endpoint.id, url=url, enabled=enabled)
|
|
||||||
changed = True
|
|
||||||
else:
|
|
||||||
changed = False
|
|
||||||
module.exit_json(changed=changed, endpoint=endpoint)
|
|
||||||
|
|
||||||
elif state == 'absent':
|
|
||||||
if endpoint is None:
|
|
||||||
changed = False
|
|
||||||
else:
|
|
||||||
cloud.delete_endpoint(endpoint.id)
|
|
||||||
changed = True
|
|
||||||
module.exit_json(changed=changed)
|
|
||||||
|
|
||||||
except sdk.exceptions.OpenStackCloudException as e:
|
|
||||||
module.fail_json(msg=str(e))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
1
plugins/modules/os_keystone_endpoint.py
Symbolic link
1
plugins/modules/os_keystone_endpoint.py
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
endpoint.py
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user