Pavel Svimbersky | b3c21f5 | 2017-09-26 15:06:31 +0200 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | # Copyright 2017 Mirantis, Inc. |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
| 16 | # todo: |
| 17 | # CRUD VirtualService |
| 18 | # CRUD Pool |
| 19 | # CRUD |
| 20 | |
| 21 | import requests |
| 22 | import os |
| 23 | import re |
| 24 | import json |
| 25 | |
| 26 | __opts__ = {} |
| 27 | |
| 28 | def _auth(**kwargs): |
| 29 | ''' |
| 30 | Set up Contrail API credentials. |
| 31 | ''' |
| 32 | cluster_ip = __pillar__['avinetworks']['api']['ip'] |
| 33 | username = __pillar__['avinetworks']['api']['user'] |
| 34 | password = __pillar__['avinetworks']['api']['password'] |
| 35 | login = requests.post('https://' + cluster_ip + '/login', |
| 36 | verify=False, |
| 37 | data={'username': username, 'password': password}) |
| 38 | return login |
| 39 | |
| 40 | |
| 41 | def _get_input_type(_input): |
| 42 | test = re.compile(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$") |
| 43 | result = test.match(_input) |
| 44 | if result: |
| 45 | return "V4" |
| 46 | return "DNS" |
| 47 | |
| 48 | |
| 49 | def logout(login): |
| 50 | cluster_ip = __pillar__['avinetworks']['api']['ip'] |
| 51 | requests.post('https://' + cluster_ip + '/logout', |
| 52 | verify=False, |
| 53 | headers={'X-CSRFToken': login.cookies['csrftoken'], |
| 54 | 'Referer': 'https://' + cluster_ip}, |
| 55 | cookies=login.cookies) |
| 56 | |
| 57 | |
| 58 | def send_request_get(_command): |
| 59 | cluster_ip = __pillar__['avinetworks']['api']['ip'] |
| 60 | login = _auth() |
| 61 | url = "https://" + os.path.join(cluster_ip, "api", _command) |
| 62 | try: |
| 63 | resp = requests.get(url, |
| 64 | verify=False, |
| 65 | cookies=dict(sessionid=login.cookies['sessionid'])) |
| 66 | except requests.exceptions.RequestException as ex: |
| 67 | print ex |
| 68 | return None |
| 69 | logout(login) |
| 70 | return resp |
| 71 | |
| 72 | |
| 73 | def send_request_post(_command, data): |
| 74 | cluster_ip = __pillar__['avinetworks']['api']['ip'] |
| 75 | login = _auth() |
| 76 | url = "https://" + os.path.join(cluster_ip, "api", _command) |
| 77 | try: |
| 78 | resp = requests.post(url, |
| 79 | verify=False, |
| 80 | headers={'X-CSRFToken': login.cookies['csrftoken'], |
| 81 | 'Referer': 'https://' + cluster_ip, |
| 82 | 'Content-Type': 'application/json'}, |
| 83 | cookies=login.cookies, |
| 84 | data=json.dumps(data)) |
| 85 | except requests.exceptions.RequestException as ex: |
| 86 | print ex |
| 87 | return None |
| 88 | logout(login) |
| 89 | return resp |
| 90 | |
| 91 | |
| 92 | def send_request_put(_command, data): |
| 93 | cluster_ip = __pillar__['avinetworks']['api']['ip'] |
| 94 | login = _auth() |
| 95 | url = "https://" + os.path.join(cluster_ip, "api", _command) |
| 96 | try: |
| 97 | resp = requests.put(url, |
| 98 | verify=False, |
| 99 | headers={'X-CSRFToken': login.cookies['csrftoken'], |
| 100 | 'Referer': 'https://' + cluster_ip, |
| 101 | 'Content-Type': 'application/json'}, |
| 102 | cookies=login.cookies, |
| 103 | data=json.dumps(data)) |
| 104 | except requests.exceptions.RequestException as ex: |
| 105 | print ex |
| 106 | return None |
| 107 | logout(login) |
| 108 | return resp |
| 109 | |
| 110 | |
| 111 | def send_request_delete(_command, uuid, **kwargs): |
| 112 | cluster_ip = __pillar__['avinetworks']['api']['ip'] |
| 113 | login = _auth() |
| 114 | url = "https://" + os.path.join(cluster_ip, "api", _command, uuid) |
| 115 | try: |
| 116 | resp = requests.delete(url, |
| 117 | verify=False, |
| 118 | headers={'X-CSRFToken': login.cookies['csrftoken'], |
| 119 | 'Referer': 'https://' + cluster_ip, |
| 120 | 'Content-Type': 'application/json'}, |
| 121 | cookies=login.cookies) |
| 122 | except requests.exceptions.RequestException as ex: |
| 123 | print ex |
| 124 | return None |
| 125 | logout(login) |
| 126 | return resp |
| 127 | |
| 128 | |
| 129 | def pool_list(**kwargs): |
| 130 | command = "pool" |
| 131 | ret = send_request_get(command) |
| 132 | return ret.json() |
| 133 | |
| 134 | |
| 135 | def pool_get(name, **kwargs): |
| 136 | pools = pool_list() |
| 137 | for pool in pools['results']: |
| 138 | if name == pool['name'] or name == pool['uuid']: |
| 139 | return pool |
| 140 | return {'result': False, |
| 141 | 'Error': "Error in the retrieving pool."} |
| 142 | |
| 143 | |
| 144 | def pool_create(name, lb_algorithm='LB_ALGORITHM_ROUND_ROBIN', server_port=80, servers=None, **kwargs): |
| 145 | command = 'pool' |
| 146 | ret = {'name': name, |
| 147 | 'changes': {}, |
| 148 | 'result': True, |
| 149 | 'comment': ''} |
| 150 | |
| 151 | if not servers: |
| 152 | ret['result'] = False |
| 153 | ret['comment'] = "Error: Server not defined" |
| 154 | return ret |
| 155 | |
| 156 | check = pool_get(name) |
| 157 | if 'Error' not in check: |
| 158 | ret['comment'] = "Pool " + name + " already exists" |
| 159 | return ret |
| 160 | |
| 161 | if __opts__['test']: |
| 162 | ret['result'] = None |
| 163 | ret['comment'] = "Pool " + name + " will be created" |
| 164 | return ret |
| 165 | |
| 166 | data = {} |
| 167 | data["lb_algorithm"] = lb_algorithm |
| 168 | data["default_server_port"] = server_port |
| 169 | data["name"] = name |
| 170 | server_data = [] |
| 171 | for server in servers: |
| 172 | servers_type = _get_input_type(server) |
| 173 | srv = {'ip': {'type': servers_type, |
| 174 | 'addr': server}} |
| 175 | server_data.append(srv) |
| 176 | data['servers'] = server_data |
| 177 | result = send_request_post(command, data) |
| 178 | if result: |
| 179 | ret['comment'] = "Pool " + name + " has been created" |
| 180 | ret['changes'] = {'Pool': {'old': '', 'new': name}} |
| 181 | else: |
| 182 | ret['result'] = False |
| 183 | ret['comment'] = {"Error": "Pool was not created", "reason": result} |
| 184 | return ret |
| 185 | |
| 186 | |
| 187 | def pool_delete(name, **kwargs): |
| 188 | command = 'pool' |
| 189 | ret = {'name': name, |
| 190 | 'changes': {}, |
| 191 | 'result': True, |
| 192 | 'comment': ''} |
| 193 | |
| 194 | check = pool_get(name) |
| 195 | if not check: |
| 196 | ret['comment'] = "Pool " + name + " is already deleted" |
| 197 | return ret |
| 198 | |
| 199 | if __opts__['test']: |
| 200 | ret['result'] = None |
| 201 | ret['comment'] = "Pool " + name + " will be deleted" |
| 202 | return ret |
| 203 | |
| 204 | result = send_request_delete(command, check['uuid']) |
| 205 | if result: |
| 206 | ret['comment'] = "Pool " + name + " has been deleted" |
| 207 | ret['changes'] = {'Pool': {'old': name, 'new': ''}} |
| 208 | else: |
| 209 | ret['result'] = False |
| 210 | ret['comment'] = "Error: Pool was not created" |
| 211 | return ret |
| 212 | |
| 213 | |
| 214 | def virtual_service_list(): |
| 215 | command = "virtualservice" |
| 216 | ret = send_request_get(command) |
| 217 | return ret.json() |
| 218 | |
| 219 | |
| 220 | def virtual_service_get(name): |
| 221 | vservices = virtual_service_list() |
| 222 | for vs in vservices['results']: |
| 223 | if name == vs['name'] or name == vs['uuid']: |
| 224 | return vs |
| 225 | return None |
| 226 | |
| 227 | |
| 228 | def virtual_service_create(): |
| 229 | command = "virtualservice" |
| 230 | vip = [{'auto_allocate_floating_ip': True, |
| 231 | 'auto_allocate_ip': True, |
| 232 | 'ipam_network_subnet': { |
| 233 | 'subnet': { |
| 234 | "mask": 24, |
| 235 | "ip_addr": { |
| 236 | "type": "V4", |
| 237 | "addr": "192.168.32.0" |
| 238 | } |
| 239 | } |
| 240 | } |
| 241 | }] |
| 242 | service = [{"port": 8080}] |
| 243 | data = {'name': "test", |
| 244 | 'services': service, |
| 245 | 'vip': vip |
| 246 | } |
| 247 | ret = send_request_post(command, data) |
| 248 | return ret.json() |
| 249 | |
| 250 | |
| 251 | def cloud_list(): |
| 252 | command = "cloud" |
| 253 | ret = send_request_get(command) |
| 254 | return ret.json() |
| 255 | |
| 256 | |
| 257 | def cloud_get(name, **kwargs): |
| 258 | clouds = cloud_list() |
| 259 | for cloud in clouds['results']: |
| 260 | if name == cloud['name'] or name == cloud['uuid']: |
| 261 | return cloud |
| 262 | return {'result': False, |
| 263 | 'Error': "Error in the retrieving cloud."} |
| 264 | |
| 265 | |
| 266 | def cloud_create(name, mtu=1500, dhcp_enabled=False, openstack=None, **kwargs): |
| 267 | command = 'cloud' |
| 268 | ret = {'name': name, |
| 269 | 'changes': {}, |
| 270 | 'result': True, |
| 271 | 'comment': ''} |
| 272 | |
| 273 | check = cloud_get(name) |
| 274 | if 'Error' not in check: |
| 275 | ret['comment'] = "Cloud " + name + " already exists" |
| 276 | return ret |
| 277 | |
| 278 | if __opts__['test']: |
| 279 | ret['result'] = None |
| 280 | ret['comment'] = "Cloud " + name + " will be created" |
| 281 | return ret |
| 282 | |
| 283 | data = {} |
| 284 | data["name"] = name |
| 285 | data["vtype"] = "CLOUD_OPENSTACK" |
| 286 | data["license_type"] = "LIC_CORES" |
| 287 | data["mtu"] = mtu |
| 288 | data["dhcp_enabled"] = dhcp_enabled |
| 289 | |
| 290 | if openstack: |
| 291 | openstack_conf = {} |
| 292 | openstack_conf['username'] = openstack['username'] |
| 293 | openstack_conf['password'] = openstack['password'] |
| 294 | openstack_conf['admin_tenant'] = openstack['admin_tenant'] |
| 295 | openstack_conf['auth_url'] = openstack['auth_url'] |
| 296 | openstack_conf['mgmt_network_name'] = openstack['mgmt_network_name'] |
| 297 | openstack_conf['privilege'] = 'WRITE_ACCESS' |
| 298 | openstack_conf['region'] = openstack['region'] |
| 299 | openstack_conf['hypervisor'] = 'KVM' |
| 300 | openstack_conf['free_floatingips'] = openstack['free_floatingips'] |
| 301 | openstack_conf['img_format'] = 'OS_IMG_FMT_QCOW2' |
| 302 | openstack_conf['use_internal_endpoints'] = openstack['use_internal_endpoints'] |
| 303 | openstack_conf['insecure'] = openstack['insecure'] |
| 304 | openstack_conf['contrail_endpoint'] = openstack['contrail_endpoint'] |
| 305 | role_mapping = {'os_role': '*', 'avi_role': openstack['avi_role']} |
| 306 | openstack_conf['role_mapping'] = role_mapping |
| 307 | data["openstack_configuration"] = openstack_conf |
| 308 | result = send_request_post(command, data) |
| 309 | if result: |
| 310 | ret['comment'] = "Cloud " + name + " has been created" |
| 311 | ret['changes'] = {'Cloud': {'old': '', 'new': name}} |
| 312 | else: |
| 313 | ret['result'] = False |
| 314 | ret['comment'] = {"Error": "Cloud was not created", "reason": result} |
| 315 | return ret |
| 316 | |
| 317 | |
| 318 | def cloud_delete(name, **kwargs): |
| 319 | command = 'cloud' |
| 320 | ret = {'name': name, |
| 321 | 'changes': {}, |
| 322 | 'result': True, |
| 323 | 'comment': ''} |
| 324 | |
| 325 | check = cloud_get(name) |
| 326 | if not check: |
| 327 | ret['comment'] = "Cloud " + name + " is already deleted" |
| 328 | return ret |
| 329 | |
| 330 | if __opts__['test']: |
| 331 | ret['result'] = None |
| 332 | ret['comment'] = "Cloud " + name + " will be deleted" |
| 333 | return ret |
| 334 | |
| 335 | result = send_request_delete(command, check['uuid']) |
| 336 | if result: |
| 337 | ret['comment'] = "Cloud " + name + " has been deleted" |
| 338 | ret['changes'] = {'Cloud': {'old': name, 'new': ''}} |
| 339 | else: |
| 340 | ret['result'] = False |
| 341 | ret['comment'] = "Error: Cloud was not created" |
| 342 | return ret |
| 343 | |
| 344 | |
| 345 | def cluster_get(): |
| 346 | command = "cluster" |
| 347 | ret = send_request_get(command) |
| 348 | return ret.json() |
| 349 | |
| 350 | |
| 351 | def cluster_update(name, nodes, virtual_ip=None, **kwargs): |
| 352 | command = 'cluster' |
| 353 | ret = {'name': name, |
| 354 | 'changes': {}, |
| 355 | 'result': True, |
| 356 | 'comment': ''} |
| 357 | |
| 358 | if __opts__['test']: |
| 359 | ret['result'] = None |
| 360 | ret['comment'] = "Cluster " + name + " will be updated" |
| 361 | return ret |
| 362 | |
| 363 | data = {} |
| 364 | data["name"] = name |
| 365 | |
| 366 | vip = {'addr': virtual_ip, |
| 367 | 'type': _get_input_type(virtual_ip)} |
| 368 | data['virtual_ip'] = vip |
| 369 | nodes_data = [] |
| 370 | for node in nodes: |
| 371 | node_type = _get_input_type(node['addr']) |
| 372 | n = {'ip': {'type': node_type, |
| 373 | 'addr': node['addr']}, |
| 374 | 'name': node['name']} |
| 375 | nodes_data.append(n) |
| 376 | data['nodes'] = nodes_data |
| 377 | |
| 378 | result = send_request_put(command, data) |
| 379 | if result: |
| 380 | ret['comment'] = "Cluster " + name + " has been updated" |
| 381 | ret['changes'] = {'Pool': {'old': 'unknown', 'new': name}} |
| 382 | else: |
| 383 | ret['result'] = False |
| 384 | ret['comment'] = {"Error": "Cluster was not updates", "reason": result.json()['error']} |
| 385 | return ret |
Pavel Svimbersky | cb1a392 | 2017-11-07 12:08:33 +0100 | [diff] [blame] | 386 | |
| 387 | |
| 388 | def user_list(): |
| 389 | command = "user" |
| 390 | ret = send_request_get(command) |
| 391 | return ret.json() |
| 392 | |
| 393 | |
| 394 | def user_get(name, **kwargs): |
| 395 | users = user_list() |
| 396 | for user in users['results']: |
| 397 | if name == user['username'] or name == user['uuid']: |
| 398 | return user |
| 399 | return {'result': False, |
| 400 | 'Error': "Error in the retrieving user " + name + "."} |
| 401 | |
| 402 | |
| 403 | def _compare_attr(origin, new): |
| 404 | if not new: |
| 405 | return origin |
| 406 | return new |
| 407 | |
| 408 | |
| 409 | def user_create(name, uuid=None, username=None, password=None, email=None, full_name=None, is_superuser=None, local=None, **kwargs): |
| 410 | command = 'user' |
| 411 | ret = {'name': name, |
| 412 | 'changes': {}, |
| 413 | 'result': True, |
| 414 | 'comment': ''} |
| 415 | |
| 416 | user = user_get(name) |
| 417 | if 'Error' not in user: |
| 418 | data = {} |
| 419 | data['username'] = _compare_attr(user['username'], username) |
| 420 | data['password'] = _compare_attr(user['password'], password) |
| 421 | data['email'] = _compare_attr(user['email'], email) |
| 422 | data['full_name'] = _compare_attr(user['full_name'], full_name) |
| 423 | data['is_superuser'] = _compare_attr(user['is_superuser'], is_superuser) |
| 424 | data['local'] = _compare_attr(user['local'], local) |
| 425 | # data['default_tenant_uuid'] = _compare_attr(user['default_tenant_uuid'], default_tenant_uuid) |
| 426 | |
| 427 | if __opts__['test']: |
| 428 | ret['changes'] = None |
| 429 | ret['comment'] = "User " + name + " will be updated" |
| 430 | return ret |
| 431 | |
| 432 | command += "/"+user["uuid"] |
| 433 | result = send_request_put(command, data) |
| 434 | ret['result'] = result |
| 435 | ret['comment'] = "User " + name + " has been updated" |
| 436 | return ret |
| 437 | |
| 438 | data = {} |
| 439 | data['username'] = username |
| 440 | data['password'] = password |
| 441 | data['email'] = email |
| 442 | data['full_name'] = full_name |
| 443 | data['is_superuser'] = is_superuser |
| 444 | data['local'] = local |
| 445 | |
| 446 | if __opts__['test']: |
| 447 | ret['changes'] = None |
| 448 | ret['comment'] = "User " + name + " will be created" |
| 449 | return ret |
| 450 | |
| 451 | result = send_request_post(command, data) |
| 452 | ret['result'] = result |
| 453 | ret['comment'] = "User " + name + " has been created" |
| 454 | return ret |
| 455 | |
| 456 | |
| 457 | def useraccount_get(): |
| 458 | command = "useraccount" |
| 459 | ret = send_request_get(command) |
| 460 | return ret.json() |
| 461 | |
| 462 | |
| 463 | def useraccount_update(old_password, password, full_name=None, email=None, **kwargs): |
| 464 | command = 'useraccount' |
| 465 | ret = {'name': "user_account", |
| 466 | 'changes': {}, |
| 467 | 'result': True, |
| 468 | 'comment': ''} |
| 469 | data = {} |
| 470 | data['old_password'] = old_password |
| 471 | data['password'] = password |
| 472 | account = useraccount_get() |
| 473 | if email: |
| 474 | data['email'] = email |
| 475 | elif (len(account["email"]) > 0): |
| 476 | data['email'] = str(account["email"]) |
| 477 | else: |
| 478 | data['email'] = "" |
| 479 | |
| 480 | if full_name: |
| 481 | data['full_name'] = full_name |
| 482 | elif (len(account["full_name"]) > 0): |
| 483 | data['full_name'] = str(account["full_name"]) |
| 484 | else: |
| 485 | data['full_name'] = "" |
| 486 | |
| 487 | if __opts__['test']: |
| 488 | ret['result'] = None |
| 489 | ret['comment'] = "User Account will be updated" |
| 490 | return ret |
| 491 | |
| 492 | send_request_put(command, data) |
| 493 | ret['result'] = True |
| 494 | ret['changes'] = data |
| 495 | ret['comment'] = "User Account has been updated" |
| 496 | return ret |