1#!/usr/local/bin/python3.8 2 3# Copyright: (c) 2017, VEXXHOST, Inc. 4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 6DOCUMENTATION = ''' 7--- 8module: endpoint 9short_description: Manage OpenStack Identity service endpoints 10author: OpenStack Ansible SIG 11description: 12 - Create, update, or delete OpenStack Identity service endpoints. If a 13 service with the same combination of I(service), I(interface) and I(region) 14 exist, the I(url) and I(state) (C(present) or C(absent)) will be updated. 15options: 16 service: 17 description: 18 - Name or id of the service. 19 required: true 20 type: str 21 endpoint_interface: 22 description: 23 - Interface of the service. 24 choices: [admin, public, internal] 25 required: true 26 type: str 27 url: 28 description: 29 - URL of the service. 30 required: true 31 type: str 32 region: 33 description: 34 - Region that the service belongs to. Note that I(region_name) is used for authentication. 35 type: str 36 enabled: 37 description: 38 - Is the service enabled. 39 default: True 40 type: bool 41 state: 42 description: 43 - Should the resource be C(present) or C(absent). 44 choices: [present, absent] 45 default: present 46 type: str 47requirements: 48 - "python >= 3.6" 49 - "openstacksdk >= 0.13.0" 50 51extends_documentation_fragment: 52- openstack.cloud.openstack 53''' 54 55EXAMPLES = ''' 56- name: Create a service for glance 57 openstack.cloud.endpoint: 58 cloud: mycloud 59 service: glance 60 endpoint_interface: public 61 url: http://controller:9292 62 region: RegionOne 63 state: present 64 65- name: Delete a service for nova 66 openstack.cloud.endpoint: 67 cloud: mycloud 68 service: nova 69 endpoint_interface: public 70 region: RegionOne 71 state: absent 72''' 73 74RETURN = ''' 75endpoint: 76 description: Dictionary describing the endpoint. 77 returned: On success when I(state) is C(present) 78 type: complex 79 contains: 80 id: 81 description: Endpoint ID. 82 type: str 83 sample: 3292f020780b4d5baf27ff7e1d224c44 84 region: 85 description: Region Name. 86 type: str 87 sample: RegionOne 88 service_id: 89 description: Service ID. 90 type: str 91 sample: b91f1318f735494a825a55388ee118f3 92 interface: 93 description: Endpoint Interface. 94 type: str 95 sample: public 96 url: 97 description: Service URL. 98 type: str 99 sample: http://controller:9292 100 enabled: 101 description: Service status. 102 type: bool 103 sample: True 104''' 105 106from ansible_collections.openstack.cloud.plugins.module_utils.openstack import OpenStackModule 107 108 109class IdentityEndpointModule(OpenStackModule): 110 argument_spec = dict( 111 service=dict(type='str', required=True), 112 endpoint_interface=dict(type='str', required=True, choices=['admin', 'public', 'internal']), 113 url=dict(type='str', required=True), 114 region=dict(type='str'), 115 enabled=dict(type='bool', default=True), 116 state=dict(type='str', default='present', choices=['absent', 'present']), 117 ) 118 119 module_kwargs = dict( 120 supports_check_mode=True 121 ) 122 123 def _needs_update(self, endpoint): 124 if endpoint.enabled != self.params['enabled']: 125 return True 126 if endpoint.url != self.params['url']: 127 return True 128 return False 129 130 def _system_state_change(self, endpoint): 131 state = self.params['state'] 132 if state == 'absent' and endpoint: 133 return True 134 135 if state == 'present': 136 if endpoint is None: 137 return True 138 return self._needs_update(endpoint) 139 140 return False 141 142 def run(self): 143 service_name_or_id = self.params['service'] 144 interface = self.params['endpoint_interface'] 145 url = self.params['url'] 146 region = self.params['region'] 147 enabled = self.params['enabled'] 148 state = self.params['state'] 149 150 service = self.conn.get_service(service_name_or_id) 151 if service is None and state == 'absent': 152 self.exit_json(changed=False) 153 154 elif service is None and state == 'present': 155 self.fail_json(msg='Service %s does not exist' % service_name_or_id) 156 157 filters = dict(service_id=service.id, interface=interface) 158 if region is not None: 159 filters['region'] = region 160 endpoints = self.conn.search_endpoints(filters=filters) 161 162 if len(endpoints) > 1: 163 self.fail_json(msg='Service %s, interface %s and region %s are ' 164 'not unique' % 165 (service_name_or_id, interface, region)) 166 elif len(endpoints) == 1: 167 endpoint = endpoints[0] 168 else: 169 endpoint = None 170 171 if self.ansible.check_mode: 172 self.exit_json(changed=self._system_state_change(endpoint)) 173 174 if state == 'present': 175 if endpoint is None: 176 result = self.conn.create_endpoint( 177 service_name_or_id=service, url=url, interface=interface, 178 region=region, enabled=enabled) 179 endpoint = result[0] 180 changed = True 181 else: 182 if self._needs_update(endpoint): 183 endpoint = self.conn.update_endpoint( 184 endpoint.id, url=url, enabled=enabled) 185 changed = True 186 else: 187 changed = False 188 self.exit_json(changed=changed, endpoint=endpoint) 189 190 elif state == 'absent': 191 if endpoint is None: 192 changed = False 193 else: 194 self.conn.delete_endpoint(endpoint.id) 195 changed = True 196 self.exit_json(changed=changed) 197 198 199def main(): 200 module = IdentityEndpointModule() 201 module() 202 203 204if __name__ == '__main__': 205 main() 206