1#!/usr/bin/python 2 3# Copyright (c) 2018 Catalyst IT Ltd. 4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 6from __future__ import absolute_import, division, print_function 7__metaclass__ = type 8 9 10ANSIBLE_METADATA = {'metadata_version': '1.1', 11 'status': ['preview'], 12 'supported_by': 'community'} 13 14 15DOCUMENTATION = ''' 16--- 17module: os_coe_cluster 18short_description: Add/Remove COE cluster from OpenStack Cloud 19extends_documentation_fragment: openstack 20version_added: "2.8" 21author: "Feilong Wang (@flwang)" 22description: 23 - Add or Remove COE cluster from the OpenStack Container Infra service. 24options: 25 availability_zone: 26 description: 27 - Ignored. Present for backwards compatibility 28 cluster_template_id: 29 description: 30 - The template ID of cluster template. 31 required: true 32 discovery_url: 33 description: 34 - Url used for cluster node discovery 35 docker_volume_size: 36 description: 37 - The size in GB of the docker volume 38 flavor_id: 39 description: 40 - The flavor of the minion node for this ClusterTemplate 41 keypair: 42 description: 43 - Name of the keypair to use. 44 labels: 45 description: 46 - One or more key/value pairs 47 master_flavor_id: 48 description: 49 - The flavor of the master node for this ClusterTemplate 50 master_count: 51 description: 52 - The number of master nodes for this cluster 53 default: 1 54 name: 55 description: 56 - Name that has to be given to the cluster template 57 required: true 58 node_count: 59 description: 60 - The number of nodes for this cluster 61 default: 1 62 state: 63 description: 64 - Indicate desired state of the resource. 65 choices: [present, absent] 66 default: present 67 timeout: 68 description: 69 - Timeout for creating the cluster in minutes. Default to 60 mins 70 if not set 71 default: 60 72requirements: ["openstacksdk"] 73''' 74 75RETURN = ''' 76id: 77 description: The cluster UUID. 78 returned: On success when I(state) is 'present' 79 type: str 80 sample: "39007a7e-ee4f-4d13-8283-b4da2e037c69" 81cluster: 82 description: Dictionary describing the cluster. 83 returned: On success when I(state) is 'present' 84 type: complex 85 contains: 86 api_address: 87 description: 88 - Api address of cluster master node 89 type: str 90 sample: https://172.24.4.30:6443 91 cluster_template_id: 92 description: The cluster_template UUID 93 type: str 94 sample: '7b1418c8-cea8-48fc-995d-52b66af9a9aa' 95 coe_version: 96 description: 97 - Version of the COE software currently running in this cluster 98 type: str 99 sample: v1.11.1 100 container_version: 101 description: 102 - "Version of the container software. Example: docker version." 103 type: str 104 sample: 1.12.6 105 created_at: 106 description: 107 - The time in UTC at which the cluster is created 108 type: str 109 sample: "2018-08-16T10:29:45+00:00" 110 create_timeout: 111 description: 112 - Timeout for creating the cluster in minutes. Default to 60 if 113 not set. 114 type: int 115 sample: 60 116 discovery_url: 117 description: 118 - Url used for cluster node discovery 119 type: str 120 sample: https://discovery.etcd.io/a42ee38e7113f31f4d6324f24367aae5 121 faults: 122 description: 123 - Fault info collected from the Heat resources of this cluster 124 type: dict 125 sample: {'0': 'ResourceInError: resources[0].resources...'} 126 flavor_id: 127 description: 128 - The flavor of the minion node for this cluster 129 type: str 130 sample: c1.c1r1 131 keypair: 132 description: 133 - Name of the keypair to use. 134 type: str 135 sample: mykey 136 labels: 137 description: One or more key/value pairs 138 type: dict 139 sample: {'key1': 'value1', 'key2': 'value2'} 140 master_addresses: 141 description: 142 - IP addresses of cluster master nodes 143 type: list 144 sample: ['172.24.4.5'] 145 master_count: 146 description: 147 - The number of master nodes for this cluster. 148 type: int 149 sample: 1 150 master_flavor_id: 151 description: 152 - The flavor of the master node for this cluster 153 type: str 154 sample: c1.c1r1 155 name: 156 description: 157 - Name that has to be given to the cluster 158 type: str 159 sample: k8scluster 160 node_addresses: 161 description: 162 - IP addresses of cluster slave nodes 163 type: list 164 sample: ['172.24.4.8'] 165 node_count: 166 description: 167 - The number of master nodes for this cluster. 168 type: int 169 sample: 1 170 stack_id: 171 description: 172 - Stack id of the Heat stack 173 type: str 174 sample: '07767ec6-85f5-44cb-bd63-242a8e7f0d9d' 175 status: 176 description: Status of the cluster from the heat stack 177 type: str 178 sample: 'CREATE_COMLETE' 179 status_reason: 180 description: 181 - Status reason of the cluster from the heat stack 182 type: str 183 sample: 'Stack CREATE completed successfully' 184 updated_at: 185 description: 186 - The time in UTC at which the cluster is updated 187 type: str 188 sample: '2018-08-16T10:39:25+00:00' 189 uuid: 190 description: 191 - Unique UUID for this cluster 192 type: str 193 sample: '86246a4d-a16c-4a58-9e96ad7719fe0f9d' 194''' 195 196EXAMPLES = ''' 197# Create a new Kubernetes cluster 198- os_coe_cluster: 199 name: k8s 200 cluster_template_id: k8s-ha 201 keypair: mykey 202 master_count: 3 203 node_count: 5 204''' 205 206from ansible.module_utils.basic import AnsibleModule 207from ansible.module_utils.openstack import openstack_full_argument_spec, openstack_module_kwargs, openstack_cloud_from_module 208 209 210def _parse_labels(labels): 211 if isinstance(labels, str): 212 labels_dict = {} 213 for kv_str in labels.split(","): 214 k, v = kv_str.split("=") 215 labels_dict[k] = v 216 return labels_dict 217 if not labels: 218 return {} 219 return labels 220 221 222def main(): 223 argument_spec = openstack_full_argument_spec( 224 cluster_template_id=dict(required=True), 225 discovery_url=dict(default=None), 226 docker_volume_size=dict(type='int'), 227 flavor_id=dict(default=None), 228 keypair=dict(default=None), 229 labels=dict(default=None, type='raw'), 230 master_count=dict(type='int', default=1), 231 master_flavor_id=dict(default=None), 232 name=dict(required=True), 233 node_count=dict(type='int', default=1), 234 state=dict(default='present', choices=['absent', 'present']), 235 timeout=dict(type='int', default=60), 236 ) 237 module_kwargs = openstack_module_kwargs() 238 module = AnsibleModule(argument_spec, **module_kwargs) 239 240 params = module.params.copy() 241 242 state = module.params['state'] 243 name = module.params['name'] 244 cluster_template_id = module.params['cluster_template_id'] 245 246 kwargs = dict( 247 discovery_url=module.params['discovery_url'], 248 docker_volume_size=module.params['docker_volume_size'], 249 flavor_id=module.params['flavor_id'], 250 keypair=module.params['keypair'], 251 labels=_parse_labels(params['labels']), 252 master_count=module.params['master_count'], 253 master_flavor_id=module.params['master_flavor_id'], 254 node_count=module.params['node_count'], 255 create_timeout=module.params['timeout'], 256 ) 257 258 sdk, cloud = openstack_cloud_from_module(module) 259 try: 260 changed = False 261 cluster = cloud.get_coe_cluster(name_or_id=name, filters={'cluster_template_id': cluster_template_id}) 262 263 if state == 'present': 264 if not cluster: 265 cluster = cloud.create_coe_cluster(name, cluster_template_id=cluster_template_id, **kwargs) 266 changed = True 267 else: 268 changed = False 269 270 module.exit_json(changed=changed, cluster=cluster, id=cluster['uuid']) 271 elif state == 'absent': 272 if not cluster: 273 module.exit_json(changed=False) 274 else: 275 cloud.delete_coe_cluster(name) 276 module.exit_json(changed=True) 277 except sdk.exceptions.OpenStackCloudException as e: 278 module.fail_json(msg=str(e), extra_data=e.extra_data) 279 280 281if __name__ == "__main__": 282 main() 283