PageRenderTime 74ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/salt/modules/bigip.py

https://bitbucket.org/bhuvanchandradv/salt
Python | 2207 lines | 1962 code | 67 blank | 178 comment | 71 complexity | efdf864ec6d8806a34e6b9274d0500c1 MD5 | raw file
Possible License(s): Apache-2.0
  1. # -*- coding: utf-8 -*-
  2. '''
  3. An execution module which can manipulate an f5 bigip via iControl REST
  4. :maturity: develop
  5. :platform: f5_bigip_11.6
  6. '''
  7. # Import python libs
  8. from __future__ import absolute_import
  9. import json
  10. import logging as logger
  11. # Import third party libs
  12. try:
  13. import requests
  14. import requests.exceptions
  15. HAS_LIBS = True
  16. except ImportError:
  17. HAS_LIBS = False
  18. # Import 3rd-party libs
  19. import salt.ext.six as six
  20. # Import salt libs
  21. import salt.utils
  22. import salt.output
  23. import salt.exceptions
  24. # Setup the logger
  25. log = logger.getLogger(__name__)
  26. # Define the module's virtual name
  27. __virtualname__ = 'bigip'
  28. def __virtual__():
  29. '''
  30. Only return if requests is installed
  31. '''
  32. if HAS_LIBS:
  33. return __virtualname__
  34. return (False, 'The bigip execution module cannot be loaded: '
  35. 'python requests library not available.')
  36. BIG_IP_URL_BASE = 'https://{host}/mgmt/tm'
  37. def _build_session(username, password, trans_label=None):
  38. '''
  39. Create a session to be used when connecting to iControl REST.
  40. '''
  41. bigip = requests.session()
  42. bigip.auth = (username, password)
  43. bigip.verify = False
  44. bigip.headers.update({'Content-Type': 'application/json'})
  45. if trans_label:
  46. #pull the trans id from the grain
  47. trans_id = __salt__['grains.get']('bigip_f5_trans:{label}'.format(label=trans_label))
  48. if trans_id:
  49. bigip.headers.update({'X-F5-REST-Coordination-Id': trans_id})
  50. else:
  51. bigip.headers.update({'X-F5-REST-Coordination-Id': None})
  52. return bigip
  53. def _load_response(response):
  54. '''
  55. Load the response from json data, return the dictionary or raw text
  56. '''
  57. try:
  58. data = json.loads(response.text)
  59. except ValueError:
  60. data = response.text
  61. ret = {'code': response.status_code, 'content': data}
  62. return ret
  63. def _load_connection_error(hostname, error):
  64. '''
  65. Format and Return a connection error
  66. '''
  67. ret = {'code': None, 'content': 'Error: Unable to connect to the bigip device: {host}\n{error}'.format(host=hostname, error=error)}
  68. return ret
  69. def _loop_payload(params):
  70. '''
  71. Pass in a dictionary of parameters, loop through them and build a payload containing,
  72. parameters who's values are not None.
  73. '''
  74. #construct the payload
  75. payload = {}
  76. #set the payload
  77. for param, value in six.iteritems(params):
  78. if value is not None:
  79. payload[param] = value
  80. return payload
  81. def _build_list(option_value, item_kind):
  82. '''
  83. pass in an option to check for a list of items, create a list of dictionary of items to set
  84. for this option
  85. '''
  86. #specify profiles if provided
  87. if option_value is not None:
  88. items = []
  89. #if user specified none, return an empty list
  90. if option_value == 'none':
  91. return items
  92. #was a list already passed in?
  93. if not isinstance(option_value, list):
  94. values = option_value.split(',')
  95. else:
  96. values = option_value
  97. for value in values:
  98. # sometimes the bigip just likes a plain ol list of items
  99. if item_kind is None:
  100. items.append(value)
  101. # other times it's picky and likes key value pairs...
  102. else:
  103. items.append({'kind': item_kind, 'name': value})
  104. return items
  105. return None
  106. def _determine_toggles(payload, toggles):
  107. '''
  108. BigIP can't make up its mind if it likes yes / no or true or false.
  109. Figure out what it likes to hear without confusing the user.
  110. '''
  111. for toggle, definition in six.iteritems(toggles):
  112. #did the user specify anything?
  113. if definition['value'] is not None:
  114. #test for yes_no toggle
  115. if (definition['value'] is True or definition['value'] == 'yes') and definition['type'] == 'yes_no':
  116. payload[toggle] = 'yes'
  117. elif (definition['value'] is False or definition['value'] == 'no') and definition['type'] == 'yes_no':
  118. payload[toggle] = 'no'
  119. #test for true_false toggle
  120. if (definition['value'] is True or definition['value'] == 'yes') and definition['type'] == 'true_false':
  121. payload[toggle] = True
  122. elif (definition['value'] is False or definition['value'] == 'no') and definition['type'] == 'true_false':
  123. payload[toggle] = False
  124. return payload
  125. def _set_value(value):
  126. '''
  127. A function to detect if user is trying to pass a dictionary or list. parse it and return a
  128. dictionary list or a string
  129. '''
  130. logger.error(value)
  131. #don't continue if already an acceptable data-type
  132. if isinstance(value, bool) or isinstance(value, dict) or isinstance(value, list):
  133. return value
  134. #check if json
  135. if value.startswith('j{') and value.endswith('}j'):
  136. value = value.replace('j{', '{')
  137. value = value.replace('}j', '}')
  138. try:
  139. return json.loads(value)
  140. except Exception:
  141. raise salt.exceptions.CommandExecutionError
  142. #detect list of dictionaries
  143. if '|' in value and r'\|' not in value:
  144. values = value.split('|')
  145. items = []
  146. for value in values:
  147. items.append(_set_value(value))
  148. return items
  149. #parse out dictionary if detected
  150. if ':' in value and r'\:' not in value:
  151. options = {}
  152. #split out pairs
  153. key_pairs = value.split(',')
  154. for key_pair in key_pairs:
  155. k = key_pair.split(':')[0]
  156. v = key_pair.split(':')[1]
  157. options[k] = v
  158. return options
  159. #try making a list
  160. elif ',' in value and r'\,' not in value:
  161. value_items = value.split(',')
  162. return value_items
  163. #just return a string
  164. else:
  165. #remove escape chars if added
  166. if r'\|' in value:
  167. value = value.replace(r'\|', '|')
  168. if r'\:' in value:
  169. value = value.replace(r'\:', ':')
  170. if r'\,' in value:
  171. value = value.replace(r'\,', ',')
  172. return value
  173. def start_transaction(hostname, username, password, label):
  174. '''
  175. A function to connect to a bigip device and start a new transaction.
  176. hostname
  177. The host/address of the bigip device
  178. username
  179. The iControl REST username
  180. password
  181. The iControl REST password
  182. label
  183. The name / alias for this transaction. The actual transaction
  184. id will be stored within a grain called ``bigip_f5_trans:<label>``
  185. CLI Example::
  186. salt '*' bigip.start_transaction bigip admin admin my_transaction
  187. '''
  188. #build the session
  189. bigip_session = _build_session(username, password)
  190. payload = {}
  191. #post to REST to get trans id
  192. try:
  193. response = bigip_session.post(BIG_IP_URL_BASE.format(host=hostname)+'/transaction', data=json.dumps(payload))
  194. except requests.exceptions.ConnectionError as e:
  195. return _load_connection_error(hostname, e)
  196. #extract the trans_id
  197. data = _load_response(response)
  198. if data['code'] == 200:
  199. trans_id = data['content']['transId']
  200. __salt__['grains.setval']('bigip_f5_trans', {label: trans_id})
  201. return 'Transaction: {trans_id} - has successfully been stored in the grain: bigip_f5_trans:{label}'.format(trans_id=trans_id,
  202. label=label)
  203. else:
  204. return data
  205. def list_transaction(hostname, username, password, label):
  206. '''
  207. A function to connect to a bigip device and list an existing transaction.
  208. hostname
  209. The host/address of the bigip device
  210. username
  211. The iControl REST username
  212. password
  213. The iControl REST password
  214. label
  215. the label of this transaction stored within the grain:
  216. ``bigip_f5_trans:<label>``
  217. CLI Example::
  218. salt '*' bigip.list_transaction bigip admin admin my_transaction
  219. '''
  220. #build the session
  221. bigip_session = _build_session(username, password)
  222. #pull the trans id from the grain
  223. trans_id = __salt__['grains.get']('bigip_f5_trans:{label}'.format(label=label))
  224. if trans_id:
  225. #post to REST to get trans id
  226. try:
  227. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/transaction/{trans_id}/commands'.format(trans_id=trans_id))
  228. return _load_response(response)
  229. except requests.exceptions.ConnectionError as e:
  230. return _load_connection_error(hostname, e)
  231. else:
  232. return 'Error: the label for this transaction was not defined as a grain. Begin a new transaction using the' \
  233. ' bigip.start_transaction function'
  234. def commit_transaction(hostname, username, password, label):
  235. '''
  236. A function to connect to a bigip device and commit an existing transaction.
  237. hostname
  238. The host/address of the bigip device
  239. username
  240. The iControl REST username
  241. password
  242. The iControl REST password
  243. label
  244. the label of this transaction stored within the grain:
  245. ``bigip_f5_trans:<label>``
  246. CLI Example::
  247. salt '*' bigip.commit_transaction bigip admin admin my_transaction
  248. '''
  249. #build the session
  250. bigip_session = _build_session(username, password)
  251. #pull the trans id from the grain
  252. trans_id = __salt__['grains.get']('bigip_f5_trans:{label}'.format(label=label))
  253. if trans_id:
  254. payload = {}
  255. payload['state'] = 'VALIDATING'
  256. #patch to REST to get trans id
  257. try:
  258. response = bigip_session.patch(BIG_IP_URL_BASE.format(host=hostname)+'/transaction/{trans_id}'.format(trans_id=trans_id), data=json.dumps(payload))
  259. return _load_response(response)
  260. except requests.exceptions.ConnectionError as e:
  261. return _load_connection_error(hostname, e)
  262. else:
  263. return 'Error: the label for this transaction was not defined as a grain. Begin a new transaction using the' \
  264. ' bigip.start_transaction function'
  265. def delete_transaction(hostname, username, password, label):
  266. '''
  267. A function to connect to a bigip device and delete an existing transaction.
  268. hostname
  269. The host/address of the bigip device
  270. username
  271. The iControl REST username
  272. password
  273. The iControl REST password
  274. label
  275. The label of this transaction stored within the grain:
  276. ``bigip_f5_trans:<label>``
  277. CLI Example::
  278. salt '*' bigip.delete_transaction bigip admin admin my_transaction
  279. '''
  280. #build the session
  281. bigip_session = _build_session(username, password)
  282. #pull the trans id from the grain
  283. trans_id = __salt__['grains.get']('bigip_f5_trans:{label}'.format(label=label))
  284. if trans_id:
  285. #patch to REST to get trans id
  286. try:
  287. response = bigip_session.delete(BIG_IP_URL_BASE.format(host=hostname)+'/transaction/{trans_id}'.format(trans_id=trans_id))
  288. return _load_response(response)
  289. except requests.exceptions.ConnectionError as e:
  290. return _load_connection_error(hostname, e)
  291. else:
  292. return 'Error: the label for this transaction was not defined as a grain. Begin a new transaction using the' \
  293. ' bigip.start_transaction function'
  294. def list_node(hostname, username, password, name=None, trans_label=None):
  295. '''
  296. A function to connect to a bigip device and list all nodes or a specific node.
  297. hostname
  298. The host/address of the bigip device
  299. username
  300. The iControl REST username
  301. password
  302. The iControl REST password
  303. name
  304. The name of the node to list. If no name is specified than all nodes
  305. will be listed.
  306. trans_label
  307. The label of the transaction stored within the grain:
  308. ``bigip_f5_trans:<label>``
  309. CLI Example::
  310. salt '*' bigip.list_node bigip admin admin my-node
  311. '''
  312. #build sessions
  313. bigip_session = _build_session(username, password, trans_label)
  314. #get to REST
  315. try:
  316. if name:
  317. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/node/{name}'.format(name=name))
  318. else:
  319. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/node')
  320. except requests.exceptions.ConnectionError as e:
  321. return _load_connection_error(hostname, e)
  322. return _load_response(response)
  323. def create_node(hostname, username, password, name, address, trans_label=None):
  324. '''
  325. A function to connect to a bigip device and create a node.
  326. hostname
  327. The host/address of the bigip device
  328. username
  329. The iControl REST username
  330. password
  331. The iControl REST password
  332. name
  333. The name of the node
  334. address
  335. The address of the node
  336. trans_label
  337. The label of the transaction stored within the grain:
  338. ``bigip_f5_trans:<label>``
  339. CLI Example::
  340. salt '*' bigip.create_node bigip admin admin 10.1.1.2
  341. '''
  342. #build session
  343. bigip_session = _build_session(username, password, trans_label)
  344. #construct the payload
  345. payload = {}
  346. payload['name'] = name
  347. payload['address'] = address
  348. #post to REST
  349. try:
  350. response = bigip_session.post(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/node', data=json.dumps(payload))
  351. except requests.exceptions.ConnectionError as e:
  352. return _load_connection_error(hostname, e)
  353. return _load_response(response)
  354. def modify_node(hostname, username, password, name,
  355. connection_limit=None,
  356. description=None,
  357. dynamic_ratio=None,
  358. logging=None,
  359. monitor=None,
  360. rate_limit=None,
  361. ratio=None,
  362. session=None,
  363. state=None,
  364. trans_label=None):
  365. '''
  366. A function to connect to a bigip device and modify an existing node.
  367. hostname
  368. The host/address of the bigip device
  369. username
  370. The iControl REST username
  371. password
  372. The iControl REST password
  373. name
  374. The name of the node to modify
  375. connection_limit
  376. [integer]
  377. description
  378. [string]
  379. dynamic_ratio
  380. [integer]
  381. logging
  382. [enabled | disabled]
  383. monitor
  384. [[name] | none | default]
  385. rate_limit
  386. [integer]
  387. ratio
  388. [integer]
  389. session
  390. [user-enabled | user-disabled]
  391. state
  392. [user-down | user-up ]
  393. trans_label
  394. The label of the transaction stored within the grain:
  395. ``bigip_f5_trans:<label>``
  396. CLI Example::
  397. salt '*' bigip.modify_node bigip admin admin 10.1.1.2 ratio=2 logging=enabled
  398. '''
  399. params = {
  400. 'connection-limit': connection_limit,
  401. 'description': description,
  402. 'dynamic-ratio': dynamic_ratio,
  403. 'logging': logging,
  404. 'monitor': monitor,
  405. 'rate-limit': rate_limit,
  406. 'ratio': ratio,
  407. 'session': session,
  408. 'state': state,
  409. }
  410. #build session
  411. bigip_session = _build_session(username, password, trans_label)
  412. #build payload
  413. payload = _loop_payload(params)
  414. payload['name'] = name
  415. #put to REST
  416. try:
  417. response = bigip_session.put(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/node/{name}'.format(name=name), data=json.dumps(payload))
  418. except requests.exceptions.ConnectionError as e:
  419. return _load_connection_error(hostname, e)
  420. return _load_response(response)
  421. def delete_node(hostname, username, password, name, trans_label=None):
  422. '''
  423. A function to connect to a bigip device and delete a specific node.
  424. hostname
  425. The host/address of the bigip device
  426. username
  427. The iControl REST username
  428. password
  429. The iControl REST password
  430. name
  431. The name of the node which will be deleted.
  432. trans_label
  433. The label of the transaction stored within the grain:
  434. ``bigip_f5_trans:<label>``
  435. CLI Example::
  436. salt '*' bigip.delete_node bigip admin admin my-node
  437. '''
  438. #build session
  439. bigip_session = _build_session(username, password, trans_label)
  440. #delete to REST
  441. try:
  442. response = bigip_session.delete(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/node/{name}'.format(name=name))
  443. except requests.exceptions.ConnectionError as e:
  444. return _load_connection_error(hostname, e)
  445. if _load_response(response) == '':
  446. return True
  447. else:
  448. return _load_response(response)
  449. def list_pool(hostname, username, password, name=None):
  450. '''
  451. A function to connect to a bigip device and list all pools or a specific pool.
  452. hostname
  453. The host/address of the bigip device
  454. username
  455. The iControl REST username
  456. password
  457. The iControl REST password
  458. name
  459. The name of the pool to list. If no name is specified then all pools
  460. will be listed.
  461. CLI Example::
  462. salt '*' bigip.list_pool bigip admin admin my-pool
  463. '''
  464. #build sessions
  465. bigip_session = _build_session(username, password)
  466. #get to REST
  467. try:
  468. if name:
  469. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/pool/{name}/?expandSubcollections=true'.format(name=name))
  470. else:
  471. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/pool')
  472. except requests.exceptions.ConnectionError as e:
  473. return _load_connection_error(hostname, e)
  474. return _load_response(response)
  475. def create_pool(hostname, username, password, name, members=None,
  476. allow_nat=None,
  477. allow_snat=None,
  478. description=None,
  479. gateway_failsafe_device=None,
  480. ignore_persisted_weight=None,
  481. ip_tos_to_client=None,
  482. ip_tos_to_server=None,
  483. link_qos_to_client=None,
  484. link_qos_to_server=None,
  485. load_balancing_mode=None,
  486. min_active_members=None,
  487. min_up_members=None,
  488. min_up_members_action=None,
  489. min_up_members_checking=None,
  490. monitor=None,
  491. profiles=None,
  492. queue_depth_limit=None,
  493. queue_on_connection_limit=None,
  494. queue_time_limit=None,
  495. reselect_tries=None,
  496. service_down_action=None,
  497. slow_ramp_time=None):
  498. '''
  499. A function to connect to a bigip device and create a pool.
  500. hostname
  501. The host/address of the bigip device
  502. username
  503. The iControl REST username
  504. password
  505. The iControl REST password
  506. name
  507. The name of the pool to create.
  508. members
  509. List of comma delimited pool members to add to the pool.
  510. i.e. 10.1.1.1:80,10.1.1.2:80,10.1.1.3:80
  511. allow_nat
  512. [yes | no]
  513. allow_snat
  514. [yes | no]
  515. description
  516. [string]
  517. gateway_failsafe_device
  518. [string]
  519. ignore_persisted_weight
  520. [enabled | disabled]
  521. ip_tos_to_client
  522. [pass-through | [integer]]
  523. ip_tos_to_server
  524. [pass-through | [integer]]
  525. link_qos_to_client
  526. [pass-through | [integer]]
  527. link_qos_to_server
  528. [pass-through | [integer]]
  529. load_balancing_mode
  530. [dynamic-ratio-member | dynamic-ratio-node |
  531. fastest-app-response | fastest-node |
  532. least-connections-members |
  533. least-connections-node |
  534. least-sessions |
  535. observed-member | observed-node |
  536. predictive-member | predictive-node |
  537. ratio-least-connections-member |
  538. ratio-least-connections-node |
  539. ratio-member | ratio-node | ratio-session |
  540. round-robin | weighted-least-connections-member |
  541. weighted-least-connections-node]
  542. min_active_members
  543. [integer]
  544. min_up_members
  545. [integer]
  546. min_up_members_action
  547. [failover | reboot | restart-all]
  548. min_up_members_checking
  549. [enabled | disabled]
  550. monitor
  551. [name]
  552. profiles
  553. [none | profile_name]
  554. queue_depth_limit
  555. [integer]
  556. queue_on_connection_limit
  557. [enabled | disabled]
  558. queue_time_limit
  559. [integer]
  560. reselect_tries
  561. [integer]
  562. service_down_action
  563. [drop | none | reselect | reset]
  564. slow_ramp_time
  565. [integer]
  566. CLI Example::
  567. salt '*' bigip.create_pool bigip admin admin my-pool 10.1.1.1:80,10.1.1.2:80,10.1.1.3:80 monitor=http
  568. '''
  569. params = {
  570. 'description': description,
  571. 'gateway-failsafe-device': gateway_failsafe_device,
  572. 'ignore-persisted-weight': ignore_persisted_weight,
  573. 'ip-tos-to-client': ip_tos_to_client,
  574. 'ip-tos-to-server': ip_tos_to_server,
  575. 'link-qos-to-client': link_qos_to_client,
  576. 'link-qos-to-server': link_qos_to_server,
  577. 'load-balancing-mode': load_balancing_mode,
  578. 'min-active-members': min_active_members,
  579. 'min-up-members': min_up_members,
  580. 'min-up-members-action': min_up_members_action,
  581. 'min-up-members-checking': min_up_members_checking,
  582. 'monitor': monitor,
  583. 'profiles': profiles,
  584. 'queue-on-connection-limit': queue_on_connection_limit,
  585. 'queue-depth-limit': queue_depth_limit,
  586. 'queue-time-limit': queue_time_limit,
  587. 'reselect-tries': reselect_tries,
  588. 'service-down-action': service_down_action,
  589. 'slow-ramp-time': slow_ramp_time
  590. }
  591. # some options take yes no others take true false. Figure out when to use which without
  592. # confusing the end user
  593. toggles = {
  594. 'allow-nat': {'type': 'yes_no', 'value': allow_nat},
  595. 'allow-snat': {'type': 'yes_no', 'value': allow_snat}
  596. }
  597. #build payload
  598. payload = _loop_payload(params)
  599. payload['name'] = name
  600. #determine toggles
  601. payload = _determine_toggles(payload, toggles)
  602. #specify members if provided
  603. if members is not None:
  604. payload['members'] = _build_list(members, 'ltm:pool:members')
  605. #build session
  606. bigip_session = _build_session(username, password)
  607. #post to REST
  608. try:
  609. response = bigip_session.post(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/pool', data=json.dumps(payload))
  610. except requests.exceptions.ConnectionError as e:
  611. return _load_connection_error(hostname, e)
  612. return _load_response(response)
  613. def modify_pool(hostname, username, password, name,
  614. allow_nat=None,
  615. allow_snat=None,
  616. description=None,
  617. gateway_failsafe_device=None,
  618. ignore_persisted_weight=None,
  619. ip_tos_to_client=None,
  620. ip_tos_to_server=None,
  621. link_qos_to_client=None,
  622. link_qos_to_server=None,
  623. load_balancing_mode=None,
  624. min_active_members=None,
  625. min_up_members=None,
  626. min_up_members_action=None,
  627. min_up_members_checking=None,
  628. monitor=None,
  629. profiles=None,
  630. queue_depth_limit=None,
  631. queue_on_connection_limit=None,
  632. queue_time_limit=None,
  633. reselect_tries=None,
  634. service_down_action=None,
  635. slow_ramp_time=None):
  636. '''
  637. A function to connect to a bigip device and modify an existing pool.
  638. hostname
  639. The host/address of the bigip device
  640. username
  641. The iControl REST username
  642. password
  643. The iControl REST password
  644. name
  645. The name of the pool to modify.
  646. allow_nat
  647. [yes | no]
  648. allow_snat
  649. [yes | no]
  650. description
  651. [string]
  652. gateway_failsafe_device
  653. [string]
  654. ignore_persisted_weight
  655. [yes | no]
  656. ip_tos_to_client
  657. [pass-through | [integer]]
  658. ip_tos_to_server
  659. [pass-through | [integer]]
  660. link_qos_to_client
  661. [pass-through | [integer]]
  662. link_qos_to_server
  663. [pass-through | [integer]]
  664. load_balancing_mode
  665. [dynamic-ratio-member | dynamic-ratio-node |
  666. fastest-app-response | fastest-node |
  667. least-connections-members |
  668. least-connections-node |
  669. least-sessions |
  670. observed-member | observed-node |
  671. predictive-member | predictive-node |
  672. ratio-least-connections-member |
  673. ratio-least-connections-node |
  674. ratio-member | ratio-node | ratio-session |
  675. round-robin | weighted-least-connections-member |
  676. weighted-least-connections-node]
  677. min_active_members
  678. [integer]
  679. min_up_members
  680. [integer]
  681. min_up_members_action
  682. [failover | reboot | restart-all]
  683. min_up_members_checking
  684. [enabled | disabled]
  685. monitor
  686. [name]
  687. profiles
  688. [none | profile_name]
  689. queue_on_connection_limit
  690. [enabled | disabled]
  691. queue_depth_limit
  692. [integer]
  693. queue_time_limit
  694. [integer]
  695. reselect_tries
  696. [integer]
  697. service_down_action
  698. [drop | none | reselect | reset]
  699. slow_ramp_time
  700. [integer]
  701. CLI Example::
  702. salt '*' bigip.modify_pool bigip admin admin my-pool 10.1.1.1:80,10.1.1.2:80,10.1.1.3:80 min_active_members=1
  703. '''
  704. params = {
  705. 'description': description,
  706. 'gateway-failsafe-device': gateway_failsafe_device,
  707. 'ignore-persisted-weight': ignore_persisted_weight,
  708. 'ip-tos-to-client': ip_tos_to_client,
  709. 'ip-tos-to-server': ip_tos_to_server,
  710. 'link-qos-to-client': link_qos_to_client,
  711. 'link-qos-to-server': link_qos_to_server,
  712. 'load-balancing-mode': load_balancing_mode,
  713. 'min-active-members': min_active_members,
  714. 'min-up-members': min_up_members,
  715. 'min-up_members-action': min_up_members_action,
  716. 'min-up-members-checking': min_up_members_checking,
  717. 'monitor': monitor,
  718. 'profiles': profiles,
  719. 'queue-on-connection-limit': queue_on_connection_limit,
  720. 'queue-depth-limit': queue_depth_limit,
  721. 'queue-time-limit': queue_time_limit,
  722. 'reselect-tries': reselect_tries,
  723. 'service-down-action': service_down_action,
  724. 'slow-ramp-time': slow_ramp_time
  725. }
  726. # some options take yes no others take true false. Figure out when to use which without
  727. # confusing the end user
  728. toggles = {
  729. 'allow-nat': {'type': 'yes_no', 'value': allow_nat},
  730. 'allow-snat': {'type': 'yes_no', 'value': allow_snat}
  731. }
  732. #build payload
  733. payload = _loop_payload(params)
  734. payload['name'] = name
  735. #determine toggles
  736. payload = _determine_toggles(payload, toggles)
  737. #build session
  738. bigip_session = _build_session(username, password)
  739. #post to REST
  740. try:
  741. response = bigip_session.put(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/pool/{name}'.format(name=name), data=json.dumps(payload))
  742. except requests.exceptions.ConnectionError as e:
  743. return _load_connection_error(hostname, e)
  744. return _load_response(response)
  745. def delete_pool(hostname, username, password, name):
  746. '''
  747. A function to connect to a bigip device and delete a specific pool.
  748. hostname
  749. The host/address of the bigip device
  750. username
  751. The iControl REST username
  752. password
  753. The iControl REST password
  754. name
  755. The name of the pool which will be deleted
  756. CLI Example::
  757. salt '*' bigip.delete_node bigip admin admin my-pool
  758. '''
  759. #build session
  760. bigip_session = _build_session(username, password)
  761. #delete to REST
  762. try:
  763. response = bigip_session.delete(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/pool/{name}'.format(name=name))
  764. except requests.exceptions.ConnectionError as e:
  765. return _load_connection_error(hostname, e)
  766. if _load_response(response) == '':
  767. return True
  768. else:
  769. return _load_response(response)
  770. def replace_pool_members(hostname, username, password, name, members):
  771. '''
  772. A function to connect to a bigip device and replace members of an existing pool with new members.
  773. hostname
  774. The host/address of the bigip device
  775. username
  776. The iControl REST username
  777. password
  778. The iControl REST password
  779. name
  780. The name of the pool to modify
  781. members
  782. List of comma delimited pool members to replace existing members with.
  783. i.e. 10.1.1.1:80,10.1.1.2:80,10.1.1.3:80
  784. CLI Example::
  785. salt '*' bigip.replace_pool_members bigip admin admin my-pool 10.2.2.1:80,10.2.2.2:80,10.2.2.3:80
  786. '''
  787. payload = {}
  788. payload['name'] = name
  789. #specify members if provided
  790. if members is not None:
  791. if isinstance(members, str):
  792. members = members.split(',')
  793. pool_members = []
  794. for member in members:
  795. #check to see if already a dictionary ( for states)
  796. if isinstance(member, dict):
  797. #check for state alternative name 'member_state', replace with state
  798. if 'member_state' in member.keys():
  799. member['state'] = member.pop('member_state')
  800. #replace underscore with dash
  801. for key in member:
  802. new_key = key.replace('_', '-')
  803. member[new_key] = member.pop(key)
  804. pool_members.append(member)
  805. #parse string passed via execution command (for executions)
  806. else:
  807. pool_members.append({'name': member, 'address': member.split(':')[0]})
  808. payload['members'] = pool_members
  809. #build session
  810. bigip_session = _build_session(username, password)
  811. #put to REST
  812. try:
  813. response = bigip_session.put(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/pool/{name}'.format(name=name), data=json.dumps(payload))
  814. except requests.exceptions.ConnectionError as e:
  815. return _load_connection_error(hostname, e)
  816. return _load_response(response)
  817. def add_pool_member(hostname, username, password, name, member):
  818. '''
  819. A function to connect to a bigip device and add a new member to an existing pool.
  820. hostname
  821. The host/address of the bigip device
  822. username
  823. The iControl REST username
  824. password
  825. The iControl REST password
  826. name
  827. The name of the pool to modify
  828. member
  829. The name of the member to add
  830. i.e. 10.1.1.2:80
  831. CLI Example:
  832. .. code-block:: bash
  833. salt '*' bigip.add_pool_members bigip admin admin my-pool 10.2.2.1:80
  834. '''
  835. # for states
  836. if isinstance(member, dict):
  837. #check for state alternative name 'member_state', replace with state
  838. if 'member_state' in member.keys():
  839. member['state'] = member.pop('member_state')
  840. #replace underscore with dash
  841. for key in member:
  842. new_key = key.replace('_', '-')
  843. member[new_key] = member.pop(key)
  844. payload = member
  845. # for execution
  846. else:
  847. payload = {'name': member, 'address': member.split(':')[0]}
  848. #build session
  849. bigip_session = _build_session(username, password)
  850. #post to REST
  851. try:
  852. response = bigip_session.post(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/pool/{name}/members'.format(name=name), data=json.dumps(payload))
  853. except requests.exceptions.ConnectionError as e:
  854. return _load_connection_error(hostname, e)
  855. return _load_response(response)
  856. def modify_pool_member(hostname, username, password, name, member,
  857. connection_limit=None,
  858. description=None,
  859. dynamic_ratio=None,
  860. inherit_profile=None,
  861. logging=None,
  862. monitor=None,
  863. priority_group=None,
  864. profiles=None,
  865. rate_limit=None,
  866. ratio=None,
  867. session=None,
  868. state=None):
  869. '''
  870. A function to connect to a bigip device and modify an existing member of a pool.
  871. hostname
  872. The host/address of the bigip device
  873. username
  874. The iControl REST username
  875. password
  876. The iControl REST password
  877. name
  878. The name of the pool to modify
  879. member
  880. The name of the member to modify i.e. 10.1.1.2:80
  881. connection_limit
  882. [integer]
  883. description
  884. [string]
  885. dynamic_ratio
  886. [integer]
  887. inherit_profile
  888. [enabled | disabled]
  889. logging
  890. [enabled | disabled]
  891. monitor
  892. [name]
  893. priority_group
  894. [integer]
  895. profiles
  896. [none | profile_name]
  897. rate_limit
  898. [integer]
  899. ratio
  900. [integer]
  901. session
  902. [user-enabled | user-disabled]
  903. state
  904. [ user-up | user-down ]
  905. CLI Example::
  906. salt '*' bigip.modify_pool_member bigip admin admin my-pool 10.2.2.1:80 state=use-down session=user-disabled
  907. '''
  908. params = {
  909. 'connection-limit': connection_limit,
  910. 'description': description,
  911. 'dynamic-ratio': dynamic_ratio,
  912. 'inherit-profile': inherit_profile,
  913. 'logging': logging,
  914. 'monitor': monitor,
  915. 'priority-group': priority_group,
  916. 'profiles': profiles,
  917. 'rate-limit': rate_limit,
  918. 'ratio': ratio,
  919. 'session': session,
  920. 'state': state
  921. }
  922. #build session
  923. bigip_session = _build_session(username, password)
  924. #build payload
  925. payload = _loop_payload(params)
  926. #put to REST
  927. try:
  928. response = bigip_session.put(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/pool/{name}/members/{member}'.format(name=name, member=member), data=json.dumps(payload))
  929. except requests.exceptions.ConnectionError as e:
  930. return _load_connection_error(hostname, e)
  931. return _load_response(response)
  932. def delete_pool_member(hostname, username, password, name, member):
  933. '''
  934. A function to connect to a bigip device and delete a specific pool.
  935. hostname
  936. The host/address of the bigip device
  937. username
  938. The iControl REST username
  939. password
  940. The iControl REST password
  941. name
  942. The name of the pool to modify
  943. member
  944. The name of the pool member to delete
  945. CLI Example::
  946. salt '*' bigip.delete_node bigip admin admin my-pool 10.2.2.2:80
  947. '''
  948. #build session
  949. bigip_session = _build_session(username, password)
  950. #delete to REST
  951. try:
  952. response = bigip_session.delete(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/pool/{name}/members/{member}'.format(name=name, member=member))
  953. except requests.exceptions.ConnectionError as e:
  954. return _load_connection_error(hostname, e)
  955. if _load_response(response) == '':
  956. return True
  957. else:
  958. return _load_response(response)
  959. def list_virtual(hostname, username, password, name=None):
  960. '''
  961. A function to connect to a bigip device and list all virtuals or a specific virtual.
  962. hostname
  963. The host/address of the bigip device
  964. username
  965. The iControl REST username
  966. password
  967. The iControl REST password
  968. name
  969. The name of the virtual to list. If no name is specified than all
  970. virtuals will be listed.
  971. CLI Example::
  972. salt '*' bigip.list_virtual bigip admin admin my-virtual
  973. '''
  974. #build sessions
  975. bigip_session = _build_session(username, password)
  976. #get to REST
  977. try:
  978. if name:
  979. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/virtual/{name}/?expandSubcollections=true'.format(name=name))
  980. else:
  981. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/virtual')
  982. except requests.exceptions.ConnectionError as e:
  983. return _load_connection_error(hostname, e)
  984. return _load_response(response)
  985. def create_virtual(hostname, username, password, name, destination,
  986. pool=None,
  987. address_status=None,
  988. auto_lasthop=None,
  989. bwc_policy=None,
  990. cmp_enabled=None,
  991. connection_limit=None,
  992. dhcp_relay=None,
  993. description=None,
  994. fallback_persistence=None,
  995. flow_eviction_policy=None,
  996. gtm_score=None,
  997. ip_forward=None,
  998. ip_protocol=None,
  999. internal=None,
  1000. twelve_forward=None,
  1001. last_hop_pool=None,
  1002. mask=None,
  1003. mirror=None,
  1004. nat64=None,
  1005. persist=None,
  1006. profiles=None,
  1007. policies=None,
  1008. rate_class=None,
  1009. rate_limit=None,
  1010. rate_limit_mode=None,
  1011. rate_limit_dst=None,
  1012. rate_limit_src=None,
  1013. rules=None,
  1014. related_rules=None,
  1015. reject=None,
  1016. source=None,
  1017. source_address_translation=None,
  1018. source_port=None,
  1019. state=None,
  1020. traffic_classes=None,
  1021. translate_address=None,
  1022. translate_port=None,
  1023. vlans=None):
  1024. r'''
  1025. A function to connect to a bigip device and create a virtual server.
  1026. hostname
  1027. The host/address of the bigip device
  1028. username
  1029. The iControl REST username
  1030. password
  1031. The iControl REST password
  1032. name
  1033. The name of the virtual to create
  1034. destination
  1035. [ [virtual_address_name:port] | [ipv4:port] | [ipv6.port] ]
  1036. pool
  1037. [ [pool_name] | none]
  1038. address_status
  1039. [yes | no]
  1040. auto_lasthop
  1041. [default | enabled | disabled ]
  1042. bwc_policy
  1043. [none] | string]
  1044. cmp_enabled
  1045. [yes | no]
  1046. dhcp_relay
  1047. [yes | no]
  1048. connection_limit
  1049. [integer]
  1050. description
  1051. [string]
  1052. state
  1053. [disabled | enabled]
  1054. fallback_persistence
  1055. [none | [profile name] ]
  1056. flow_eviction_policy
  1057. [none | [eviction policy name] ]
  1058. gtm_score
  1059. [integer]
  1060. ip_forward
  1061. [yes | no]
  1062. ip_protocol
  1063. [any | protocol]
  1064. internal
  1065. [yes | no]
  1066. twelve_forward
  1067. (12-forward)
  1068. [yes | no]
  1069. last_hop-pool
  1070. [ [pool_name] | none]
  1071. mask
  1072. { [ipv4] | [ipv6] }
  1073. mirror
  1074. { [disabled | enabled | none] }
  1075. nat64
  1076. [enabled | disabled]
  1077. persist
  1078. [none | profile1,profile2,profile3 ... ]
  1079. profiles
  1080. [none | default | profile1,profile2,profile3 ... ]
  1081. policies
  1082. [none | default | policy1,policy2,policy3 ... ]
  1083. rate_class
  1084. [name]
  1085. rate_limit
  1086. [integer]
  1087. rate_limit_mode
  1088. [destination | object | object-destination |
  1089. object-source | object-source-destination |
  1090. source | source-destination]
  1091. rate_limit_dst
  1092. [integer]
  1093. rate_limitçsrc
  1094. [integer]
  1095. rules
  1096. [none | [rule_one,rule_two ...] ]
  1097. related_rules
  1098. [none | [rule_one,rule_two ...] ]
  1099. reject
  1100. [yes | no]
  1101. source
  1102. { [ipv4[/prefixlen]] | [ipv6[/prefixlen]] }
  1103. source_address_translation
  1104. [none | snat:pool_name | lsn | automap ]
  1105. source_port
  1106. [change | preserve | preserve-strict]
  1107. state
  1108. [enabled | disabled]
  1109. traffic_classes
  1110. [none | default | class_one,class_two ... ]
  1111. translate_address
  1112. [enabled | disabled]
  1113. translate_port
  1114. [enabled | disabled]
  1115. vlans
  1116. [none | default | [enabled|disabled]:vlan1,vlan2,vlan3 ... ]
  1117. CLI Examples::
  1118. salt '*' bigip.create_virtual bigip admin admin my-virtual-3 26.2.2.5:80 \
  1119. pool=my-http-pool-http profiles=http,tcp
  1120. salt '*' bigip.create_virtual bigip admin admin my-virtual-3 43.2.2.5:80 \
  1121. pool=test-http-pool-http profiles=http,websecurity persist=cookie,hash \
  1122. policies=asm_auto_l7_policy__http-virtual \
  1123. rules=_sys_APM_ExchangeSupport_helper,_sys_https_redirect \
  1124. related_rules=_sys_APM_activesync,_sys_APM_ExchangeSupport_helper \
  1125. source_address_translation=snat:my-snat-pool \
  1126. translate_address=enabled translate_port=enabled \
  1127. traffic_classes=my-class,other-class \
  1128. vlans=enabled:external,internal
  1129. '''
  1130. params = {
  1131. 'pool': pool,
  1132. 'auto-lasthop': auto_lasthop,
  1133. 'bwc-policy': bwc_policy,
  1134. 'connection-limit': connection_limit,
  1135. 'description': description,
  1136. 'fallback-persistence': fallback_persistence,
  1137. 'flow-eviction-policy': flow_eviction_policy,
  1138. 'gtm-score': gtm_score,
  1139. 'ip-protocol': ip_protocol,
  1140. 'last-hop-pool': last_hop_pool,
  1141. 'mask': mask,
  1142. 'mirror': mirror,
  1143. 'nat64': nat64,
  1144. 'persist': persist,
  1145. 'rate-class': rate_class,
  1146. 'rate-limit': rate_limit,
  1147. 'rate-limit-mode': rate_limit_mode,
  1148. 'rate-limit-dst': rate_limit_dst,
  1149. 'rate-limit-src': rate_limit_src,
  1150. 'source': source,
  1151. 'source-port': source_port,
  1152. 'translate-address': translate_address,
  1153. 'translate-port': translate_port
  1154. }
  1155. # some options take yes no others take true false. Figure out when to use which without
  1156. # confusing the end user
  1157. toggles = {
  1158. 'address-status': {'type': 'yes_no', 'value': address_status},
  1159. 'cmp-enabled': {'type': 'yes_no', 'value': cmp_enabled},
  1160. 'dhcp-relay': {'type': 'true_false', 'value': dhcp_relay},
  1161. 'reject': {'type': 'true_false', 'value': reject},
  1162. '12-forward': {'type': 'true_false', 'value': twelve_forward},
  1163. 'internal': {'type': 'true_false', 'value': internal},
  1164. 'ip-forward': {'type': 'true_false', 'value': ip_forward}
  1165. }
  1166. #build session
  1167. bigip_session = _build_session(username, password)
  1168. #build payload
  1169. payload = _loop_payload(params)
  1170. payload['name'] = name
  1171. payload['destination'] = destination
  1172. #determine toggles
  1173. payload = _determine_toggles(payload, toggles)
  1174. #specify profiles if provided
  1175. if profiles is not None:
  1176. payload['profiles'] = _build_list(profiles, 'ltm:virtual:profile')
  1177. #specify persist if provided
  1178. if persist is not None:
  1179. payload['persist'] = _build_list(persist, 'ltm:virtual:persist')
  1180. #specify policies if provided
  1181. if policies is not None:
  1182. payload['policies'] = _build_list(policies, 'ltm:virtual:policy')
  1183. #specify rules if provided
  1184. if rules is not None:
  1185. payload['rules'] = _build_list(rules, None)
  1186. #specify related-rules if provided
  1187. if related_rules is not None:
  1188. payload['related-rules'] = _build_list(related_rules, None)
  1189. #handle source-address-translation
  1190. if source_address_translation is not None:
  1191. #check to see if this is already a dictionary first
  1192. if isinstance(source_address_translation, dict):
  1193. payload['source-address-translation'] = source_address_translation
  1194. elif source_address_translation == 'none':
  1195. payload['source-address-translation'] = {'pool': 'none', 'type': 'none'}
  1196. elif source_address_translation == 'automap':
  1197. payload['source-address-translation'] = {'pool': 'none', 'type': 'automap'}
  1198. elif source_address_translation == 'lsn':
  1199. payload['source-address-translation'] = {'pool': 'none', 'type': 'lsn'}
  1200. elif source_address_translation.startswith('snat'):
  1201. snat_pool = source_address_translation.split(':')[1]
  1202. payload['source-address-translation'] = {'pool': snat_pool, 'type': 'snat'}
  1203. #specify related-rules if provided
  1204. if traffic_classes is not None:
  1205. payload['traffic-classes'] = _build_list(traffic_classes, None)
  1206. #handle vlans
  1207. if vlans is not None:
  1208. #ceck to see if vlans is a dictionary (used when state makes use of function)
  1209. if isinstance(vlans, dict):
  1210. try:
  1211. payload['vlans'] = vlans['vlan_ids']
  1212. if vlans['enabled']:
  1213. payload['vlans-enabled'] = True
  1214. elif vlans['disabled']:
  1215. payload['vlans-disabled'] = True
  1216. except Exception:
  1217. return 'Error: Unable to Parse vlans dictionary: \n\tvlans={vlans}'.format(vlans=vlans)
  1218. elif vlans == 'none':
  1219. payload['vlans'] = 'none'
  1220. elif vlans == 'default':
  1221. payload['vlans'] = 'default'
  1222. elif isinstance(vlans, str) and (vlans.startswith('enabled') or vlans.startswith('disabled')):
  1223. try:
  1224. vlans_setting = vlans.split(':')[0]
  1225. payload['vlans'] = vlans.split(':')[1].split(',')
  1226. if vlans_setting == 'disabled':
  1227. payload['vlans-disabled'] = True
  1228. elif vlans_setting == 'enabled':
  1229. payload['vlans-enabled'] = True
  1230. except Exception:
  1231. return 'Error: Unable to Parse vlans option: \n\tvlans={vlans}'.format(vlans=vlans)
  1232. else:
  1233. return 'Error: vlans must be a dictionary or string.'
  1234. #determine state
  1235. if state is not None:
  1236. if state == 'enabled':
  1237. payload['enabled'] = True
  1238. elif state == 'disabled':
  1239. payload['disabled'] = True
  1240. #post to REST
  1241. try:
  1242. response = bigip_session.post(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/virtual', data=json.dumps(payload))
  1243. except requests.exceptions.ConnectionError as e:
  1244. return _load_connection_error(hostname, e)
  1245. return _load_response(response)
  1246. def modify_virtual(hostname, username, password, name,
  1247. destination=None,
  1248. pool=None,
  1249. address_status=None,
  1250. auto_lasthop=None,
  1251. bwc_policy=None,
  1252. cmp_enabled=None,
  1253. connection_limit=None,
  1254. dhcp_relay=None,
  1255. description=None,
  1256. fallback_persistence=None,
  1257. flow_eviction_policy=None,
  1258. gtm_score=None,
  1259. ip_forward=None,
  1260. ip_protocol=None,
  1261. internal=None,
  1262. twelve_forward=None,
  1263. last_hop_pool=None,
  1264. mask=None,
  1265. mirror=None,
  1266. nat64=None,
  1267. persist=None,
  1268. profiles=None,
  1269. policies=None,
  1270. rate_class=None,
  1271. rate_limit=None,
  1272. rate_limit_mode=None,
  1273. rate_limit_dst=None,
  1274. rate_limit_src=None,
  1275. rules=None,
  1276. related_rules=None,
  1277. reject=None,
  1278. source=None,
  1279. source_address_translation=None,
  1280. source_port=None,
  1281. state=None,
  1282. traffic_classes=None,
  1283. translate_address=None,
  1284. translate_port=None,
  1285. vlans=None):
  1286. '''
  1287. A function to connect to a bigip device and modify an existing virtual server.
  1288. hostname
  1289. The host/address of the bigip device
  1290. username
  1291. The iControl REST username
  1292. password
  1293. The iControl REST password
  1294. name
  1295. The name of the virtual to modify
  1296. destination
  1297. [ [virtual_address_name:port] | [ipv4:port] | [ipv6.port] ]
  1298. pool
  1299. [ [pool_name] | none]
  1300. address_status
  1301. [yes | no]
  1302. auto_lasthop
  1303. [default | enabled | disabled ]
  1304. bwc_policy
  1305. [none] | string]
  1306. cmp_enabled
  1307. [yes | no]
  1308. dhcp_relay
  1309. [yes | no}
  1310. connection_limit
  1311. [integer]
  1312. description
  1313. [string]
  1314. state
  1315. [disabled | enabled]
  1316. fallback_persistence
  1317. [none | [profile name] ]
  1318. flow_eviction_policy
  1319. [none | [eviction policy name] ]
  1320. gtm_score
  1321. [integer]
  1322. ip_forward
  1323. [yes | no]
  1324. ip_protocol
  1325. [any | protocol]
  1326. internal
  1327. [yes | no]
  1328. twelve_forward
  1329. (12-forward)
  1330. [yes | no]
  1331. last_hop-pool
  1332. [ [pool_name] | none]
  1333. mask
  1334. { [ipv4] | [ipv6] }
  1335. mirror
  1336. { [disabled | enabled | none] }
  1337. nat64
  1338. [enabled | disabled]
  1339. persist
  1340. [none | profile1,profile2,profile3 ... ]
  1341. profiles
  1342. [none | default | profile1,profile2,profile3 ... ]
  1343. policies
  1344. [none | default | policy1,policy2,policy3 ... ]
  1345. rate_class
  1346. [name]
  1347. rate_limit
  1348. [integer]
  1349. rate_limitr_mode
  1350. [destination | object | object-destination |
  1351. object-source | object-source-destination |
  1352. source | source-destination]
  1353. rate_limit_dst
  1354. [integer]
  1355. rate_limit_src
  1356. [integer]
  1357. rules
  1358. [none | [rule_one,rule_two ...] ]
  1359. related_rules
  1360. [none | [rule_one,rule_two ...] ]
  1361. reject
  1362. [yes | no]
  1363. source
  1364. { [ipv4[/prefixlen]] | [ipv6[/prefixlen]] }
  1365. source_address_translation
  1366. [none | snat:pool_name | lsn | automap ]
  1367. source_port
  1368. [change | preserve | preserve-strict]
  1369. state
  1370. [enabled | disable]
  1371. traffic_classes
  1372. [none | default | class_one,class_two ... ]
  1373. translate_address
  1374. [enabled | disabled]
  1375. translate_port
  1376. [enabled | disabled]
  1377. vlans
  1378. [none | default | [enabled|disabled]:vlan1,vlan2,vlan3 ... ]
  1379. CLI Example::
  1380. salt '*' bigip.modify_virtual bigip admin admin my-virtual source_address_translation=none
  1381. salt '*' bigip.modify_virtual bigip admin admin my-virtual rules=my-rule,my-other-rule
  1382. '''
  1383. params = {
  1384. 'destination': destination,
  1385. 'pool': pool,
  1386. 'auto-lasthop': auto_lasthop,
  1387. 'bwc-policy': bwc_policy,
  1388. 'connection-limit': connection_limit,
  1389. 'description': description,
  1390. 'fallback-persistence': fallback_persistence,
  1391. 'flow-eviction-policy': flow_eviction_policy,
  1392. 'gtm-score': gtm_score,
  1393. 'ip-protocol': ip_protocol,
  1394. 'last-hop-pool': last_hop_pool,
  1395. 'mask': mask,
  1396. 'mirror': mirror,
  1397. 'nat64': nat64,
  1398. 'persist': persist,
  1399. 'rate-class': rate_class,
  1400. 'rate-limit': rate_limit,
  1401. 'rate-limit-mode': rate_limit_mode,
  1402. 'rate-limit-dst': rate_limit_dst,
  1403. 'rate-limit-src': rate_limit_src,
  1404. 'source': source,
  1405. 'source-port': source_port,
  1406. 'translate-address': translate_address,
  1407. 'translate-port': translate_port
  1408. }
  1409. # some options take yes no others take true false. Figure out when to use which without
  1410. # confusing the end user
  1411. toggles = {
  1412. 'address-status': {'type': 'yes_no', 'value': address_status},
  1413. 'cmp-enabled': {'type': 'yes_no', 'value': cmp_enabled},
  1414. 'dhcp-relay': {'type': 'true_false', 'value': dhcp_relay},
  1415. 'reject': {'type': 'true_false', 'value': reject},
  1416. '12-forward': {'type': 'true_false', 'value': twelve_forward},
  1417. 'internal': {'type': 'true_false', 'value': internal},
  1418. 'ip-forward': {'type': 'true_false', 'value': ip_forward}
  1419. }
  1420. #build session
  1421. bigip_session = _build_session(username, password)
  1422. #build payload
  1423. payload = _loop_payload(params)
  1424. payload['name'] = name
  1425. #determine toggles
  1426. payload = _determine_toggles(payload, toggles)
  1427. #specify profiles if provided
  1428. if profiles is not None:
  1429. payload['profiles'] = _build_list(profiles, 'ltm:virtual:profile')
  1430. #specify persist if provided
  1431. if persist is not None:
  1432. payload['persist'] = _build_list(persist, 'ltm:virtual:persist')
  1433. #specify policies if provided
  1434. if policies is not None:
  1435. payload['policies'] = _build_list(policies, 'ltm:virtual:policy')
  1436. #specify rules if provided
  1437. if rules is not None:
  1438. payload['rules'] = _build_list(rules, None)
  1439. #specify related-rules if provided
  1440. if related_rules is not None:
  1441. payload['related-rules'] = _build_list(related_rules, None)
  1442. #handle source-address-translation
  1443. if source_address_translation is not None:
  1444. if source_address_translation == 'none':
  1445. payload['source-address-translation'] = {'pool': 'none', 'type': 'none'}
  1446. elif source_address_translation == 'automap':
  1447. payload['source-address-translation'] = {'pool': 'none', 'type': 'automap'}
  1448. elif source_address_translation == 'lsn':
  1449. payload['source-address-translation'] = {'pool': 'none', 'type': 'lsn'}
  1450. elif source_address_translation.startswith('snat'):
  1451. snat_pool = source_address_translation.split(':')[1]
  1452. payload['source-address-translation'] = {'pool': snat_pool, 'type': 'snat'}
  1453. #specify related-rules if provided
  1454. if traffic_classes is not None:
  1455. payload['traffic-classes'] = _build_list(traffic_classes, None)
  1456. #handle vlans
  1457. if vlans is not None:
  1458. #ceck to see if vlans is a dictionary (used when state makes use of function)
  1459. if isinstance(vlans, dict):
  1460. try:
  1461. payload['vlans'] = vlans['vlan_ids']
  1462. if vlans['enabled']:
  1463. payload['vlans-enabled'] = True
  1464. elif vlans['disabled']:
  1465. payload['vlans-disabled'] = True
  1466. except Exception:
  1467. return 'Error: Unable to Parse vlans dictionary: \n\tvlans={vlans}'.format(vlans=vlans)
  1468. elif vlans == 'none':
  1469. payload['vlans'] = 'none'
  1470. elif vlans == 'default':
  1471. payload['vlans'] = 'default'
  1472. elif vlans.startswith('enabled') or vlans.startswith('disabled'):
  1473. try:
  1474. vlans_setting = vlans.split(':')[0]
  1475. payload['vlans'] = vlans.split(':')[1].split(',')
  1476. if vlans_setting == 'disabled':
  1477. payload['vlans-disabled'] = True
  1478. elif vlans_setting == 'enabled':
  1479. payload['vlans-enabled'] = True
  1480. except Exception:
  1481. return 'Error: Unable to Parse vlans option: \n\tvlans={vlans}'.format(vlans=vlans)
  1482. #determine state
  1483. if state is not None:
  1484. if state == 'enabled':
  1485. payload['enabled'] = True
  1486. elif state == 'disabled':
  1487. payload['disabled'] = True
  1488. #put to REST
  1489. try:
  1490. response = bigip_session.put(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/virtual/{name}'.format(name=name), data=json.dumps(payload))
  1491. except requests.exceptions.ConnectionError as e:
  1492. return _load_connection_error(hostname, e)
  1493. return _load_response(response)
  1494. def delete_virtual(hostname, username, password, name):
  1495. '''
  1496. A function to connect to a bigip device and delete a specific virtual.
  1497. hostname
  1498. The host/address of the bigip device
  1499. username
  1500. The iControl REST username
  1501. password
  1502. The iControl REST password
  1503. name
  1504. The name of the virtual to delete
  1505. CLI Example::
  1506. salt '*' bigip.delete_virtual bigip admin admin my-virtual
  1507. '''
  1508. #build session
  1509. bigip_session = _build_session(username, password)
  1510. #delete to REST
  1511. try:
  1512. response = bigip_session.delete(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/virtual/{name}'.format(name=name))
  1513. except requests.exceptions.ConnectionError as e:
  1514. return _load_connection_error(hostname, e)
  1515. if _load_response(response) == '':
  1516. return True
  1517. else:
  1518. return _load_response(response)
  1519. def list_monitor(hostname, username, password, monitor_type, name=None, ):
  1520. '''
  1521. A function to connect to a bigip device and list an existing monitor. If no name is provided than all
  1522. monitors of the specified type will be listed.
  1523. hostname
  1524. The host/address of the bigip device
  1525. username
  1526. The iControl REST username
  1527. password
  1528. The iControl REST password
  1529. monitor_type
  1530. The type of monitor(s) to list
  1531. name
  1532. The name of the monitor to list
  1533. CLI Example::
  1534. salt '*' bigip.list_monitor bigip admin admin http my-http-monitor
  1535. '''
  1536. #build sessions
  1537. bigip_session = _build_session(username, password)
  1538. #get to REST
  1539. try:
  1540. if name:
  1541. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/monitor/{type}/{name}?expandSubcollections=true'.format(type=monitor_type, name=name))
  1542. else:
  1543. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/monitor/{type}'.format(type=monitor_type))
  1544. except requests.exceptions.ConnectionError as e:
  1545. return _load_connection_error(hostname, e)
  1546. return _load_response(response)
  1547. def create_monitor(hostname, username, password, monitor_type, name, **kwargs):
  1548. '''
  1549. A function to connect to a bigip device and create a monitor.
  1550. hostname
  1551. The host/address of the bigip device
  1552. username
  1553. The iControl REST username
  1554. password
  1555. The iControl REST password
  1556. monitor_type
  1557. The type of monitor to create
  1558. name
  1559. The name of the monitor to create
  1560. kwargs
  1561. Consult F5 BIGIP user guide for specific options for each monitor type.
  1562. Typically, tmsh arg names are used.
  1563. CLI Example::
  1564. salt '*' bigip.create_monitor bigip admin admin http my-http-monitor timeout=10 interval=5
  1565. '''
  1566. #build session
  1567. bigip_session = _build_session(username, password)
  1568. #construct the payload
  1569. payload = {}
  1570. payload['name'] = name
  1571. #there's a ton of different monitors and a ton of options for each type of monitor.
  1572. #this logic relies that the end user knows which options are meant for which monitor types
  1573. for key, value in six.iteritems(kwargs):
  1574. if not key.startswith('__'):
  1575. if key not in ['hostname', 'username', 'password', 'type']:
  1576. key = key.replace('_', '-')
  1577. payload[key] = value
  1578. #post to REST
  1579. try:
  1580. response = bigip_session.post(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/monitor/{type}'.format(type=monitor_type), data=json.dumps(payload))
  1581. except requests.exceptions.ConnectionError as e:
  1582. return _load_connection_error(hostname, e)
  1583. return _load_response(response)
  1584. def modify_monitor(hostname, username, password, monitor_type, name, **kwargs):
  1585. '''
  1586. A function to connect to a bigip device and modify an existing monitor.
  1587. hostname
  1588. The host/address of the bigip device
  1589. username
  1590. The iControl REST username
  1591. password
  1592. The iControl REST password
  1593. monitor_type
  1594. The type of monitor to modify
  1595. name
  1596. The name of the monitor to modify
  1597. kwargs
  1598. Consult F5 BIGIP user guide for specific options for each monitor type.
  1599. Typically, tmsh arg names are used.
  1600. CLI Example::
  1601. salt '*' bigip.modify_monitor bigip admin admin http my-http-monitor timout=16 interval=6
  1602. '''
  1603. #build session
  1604. bigip_session = _build_session(username, password)
  1605. #construct the payload
  1606. payload = {}
  1607. #there's a ton of different monitors and a ton of options for each type of monitor.
  1608. #this logic relies that the end user knows which options are meant for which monitor types
  1609. for key, value in six.iteritems(kwargs):
  1610. if not key.startswith('__'):
  1611. if key not in ['hostname', 'username', 'password', 'type', 'name']:
  1612. key = key.replace('_', '-')
  1613. payload[key] = value
  1614. #put to REST
  1615. try:
  1616. response = bigip_session.put(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/monitor/{type}/{name}'.format(type=monitor_type, name=name), data=json.dumps(payload))
  1617. except requests.exceptions.ConnectionError as e:
  1618. return _load_connection_error(hostname, e)
  1619. return _load_response(response)
  1620. def delete_monitor(hostname, username, password, monitor_type, name):
  1621. '''
  1622. A function to connect to a bigip device and delete an existing monitor.
  1623. hostname
  1624. The host/address of the bigip device
  1625. username
  1626. The iControl REST username
  1627. password
  1628. The iControl REST password
  1629. monitor_type
  1630. The type of monitor to delete
  1631. name
  1632. The name of the monitor to delete
  1633. CLI Example::
  1634. salt '*' bigip.delete_monitor bigip admin admin http my-http-monitor
  1635. '''
  1636. #build sessions
  1637. bigip_session = _build_session(username, password)
  1638. #delete to REST
  1639. try:
  1640. response = bigip_session.delete(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/monitor/{type}/{name}'.format(type=monitor_type, name=name))
  1641. except requests.exceptions.ConnectionError as e:
  1642. return _load_connection_error(hostname, e)
  1643. if _load_response(response) == '':
  1644. return True
  1645. else:
  1646. return _load_response(response)
  1647. def list_profile(hostname, username, password, profile_type, name=None, ):
  1648. '''
  1649. A function to connect to a bigip device and list an existing profile. If no name is provided than all
  1650. profiles of the specified type will be listed.
  1651. hostname
  1652. The host/address of the bigip device
  1653. username
  1654. The iControl REST username
  1655. password
  1656. The iControl REST password
  1657. profile_type
  1658. The type of profile(s) to list
  1659. name
  1660. The name of the profile to list
  1661. CLI Example::
  1662. salt '*' bigip.list_profile bigip admin admin http my-http-profile
  1663. '''
  1664. #build sessions
  1665. bigip_session = _build_session(username, password)
  1666. #get to REST
  1667. try:
  1668. if name:
  1669. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/profile/{type}/{name}?expandSubcollections=true'.format(type=profile_type, name=name))
  1670. else:
  1671. response = bigip_session.get(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/profile/{type}'.format(type=profile_type))
  1672. except requests.exceptions.ConnectionError as e:
  1673. return _load_connection_error(hostname, e)
  1674. return _load_response(response)
  1675. def create_profile(hostname, username, password, profile_type, name, **kwargs):
  1676. r'''
  1677. A function to connect to a bigip device and create a profile.
  1678. hostname
  1679. The host/address of the bigip device
  1680. username
  1681. The iControl REST username
  1682. password
  1683. The iControl REST password
  1684. profile_type
  1685. The type of profile to create
  1686. name
  1687. The name of the profile to create
  1688. kwargs
  1689. ``[ arg=val ] ... [arg=key1:val1,key2:val2] ...``
  1690. Consult F5 BIGIP user guide for specific options for each monitor type.
  1691. Typically, tmsh arg names are used.
  1692. Creating Complex Args
  1693. Profiles can get pretty complicated in terms of the amount of possible
  1694. config options. Use the following shorthand to create complex arguments such
  1695. as lists, dictionaries, and lists of dictionaries. An option is also
  1696. provided to pass raw json as well.
  1697. lists ``[i,i,i]``:
  1698. ``param='item1,item2,item3'``
  1699. Dictionary ``[k:v,k:v,k,v]``:
  1700. ``param='key-1:val-1,key-2:val2,key-3:va-3'``
  1701. List of Dictionaries ``[k:v,k:v|k:v,k:v|k:v,k:v]``:
  1702. ``param='key-1:val-1,key-2:val-2|key-1:val-1,key-2:val-2|key-1:val-1,key-2:val-2'``
  1703. JSON: ``'j{ ... }j'``:
  1704. ``cert-key-chain='j{ "default": { "cert": "default.crt", "chain": "default.crt", "key": "default.key" } }j'``
  1705. Escaping Delimiters:
  1706. Use ``\,`` or ``\:`` or ``\|`` to escape characters which shouldn't
  1707. be treated as delimiters i.e. ``ciphers='DEFAULT\:!SSLv3'``
  1708. CLI Examples::
  1709. salt '*' bigip.create_profile bigip admin admin http my-http-profile defaultsFrom='/Common/http'
  1710. salt '*' bigip.create_profile bigip admin admin http my-http-profile defaultsFrom='/Common/http' \
  1711. enforcement=maxHeaderCount:3200,maxRequests:10
  1712. '''
  1713. #build session
  1714. bigip_session = _build_session(username, password)
  1715. #construct the payload
  1716. payload = {}
  1717. payload['name'] = name
  1718. #there's a ton of different profiles and a ton of options for each type of profile.
  1719. #this logic relies that the end user knows which options are meant for which profile types
  1720. for key, value in six.iteritems(kwargs):
  1721. if not key.startswith('__'):
  1722. if key not in ['hostname', 'username', 'password', 'profile_type']:
  1723. key = key.replace('_', '-')
  1724. try:
  1725. payload[key] = _set_value(value)
  1726. except salt.exceptions.CommandExecutionError:
  1727. return 'Error: Unable to Parse JSON data for parameter: {key}\n{value}'.format(key=key, value=value)
  1728. #post to REST
  1729. try:
  1730. response = bigip_session.post(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/profile/{type}'.format(type=profile_type), data=json.dumps(payload))
  1731. except requests.exceptions.ConnectionError as e:
  1732. return _load_connection_error(hostname, e)
  1733. return _load_response(response)
  1734. def modify_profile(hostname, username, password, profile_type, name, **kwargs):
  1735. r'''
  1736. A function to connect to a bigip device and create a profile.
  1737. A function to connect to a bigip device and create a profile.
  1738. hostname
  1739. The host/address of the bigip device
  1740. username
  1741. The iControl REST username
  1742. password
  1743. The iControl REST password
  1744. profile_type
  1745. The type of profile to create
  1746. name
  1747. The name of the profile to create
  1748. kwargs
  1749. ``[ arg=val ] ... [arg=key1:val1,key2:val2] ...``
  1750. Consult F5 BIGIP user guide for specific options for each monitor type.
  1751. Typically, tmsh arg names are used.
  1752. Creating Complex Args
  1753. Profiles can get pretty complicated in terms of the amount of possible
  1754. config options. Use the following shorthand to create complex arguments such
  1755. as lists, dictionaries, and lists of dictionaries. An option is also
  1756. provided to pass raw json as well.
  1757. lists ``[i,i,i]``:
  1758. ``param='item1,item2,item3'``
  1759. Dictionary ``[k:v,k:v,k,v]``:
  1760. ``param='key-1:val-1,key-2:val2,key-3:va-3'``
  1761. List of Dictionaries ``[k:v,k:v|k:v,k:v|k:v,k:v]``:
  1762. ``param='key-1:val-1,key-2:val-2|key-1:val-1,key-2:val-2|key-1:val-1,key-2:val-2'``
  1763. JSON: ``'j{ ... }j'``:
  1764. ``cert-key-chain='j{ "default": { "cert": "default.crt", "chain": "default.crt", "key": "default.key" } }j'``
  1765. Escaping Delimiters:
  1766. Use ``\,`` or ``\:`` or ``\|`` to escape characters which shouldn't
  1767. be treated as delimiters i.e. ``ciphers='DEFAULT\:!SSLv3'``
  1768. CLI Examples::
  1769. salt '*' bigip.modify_profile bigip admin admin http my-http-profile defaultsFrom='/Common/http'
  1770. salt '*' bigip.modify_profile bigip admin admin http my-http-profile defaultsFrom='/Common/http' \
  1771. enforcement=maxHeaderCount:3200,maxRequests:10
  1772. salt '*' bigip.modify_profile bigip admin admin client-ssl my-client-ssl-1 retainCertificate=false \
  1773. ciphers='DEFAULT\:!SSLv3'
  1774. cert_key_chain='j{ "default": { "cert": "default.crt", "chain": "default.crt", "key": "default.key" } }j'
  1775. '''
  1776. #build session
  1777. bigip_session = _build_session(username, password)
  1778. #construct the payload
  1779. payload = {}
  1780. payload['name'] = name
  1781. #there's a ton of different profiles and a ton of options for each type of profile.
  1782. #this logic relies that the end user knows which options are meant for which profile types
  1783. for key, value in six.iteritems(kwargs):
  1784. if not key.startswith('__'):
  1785. if key not in ['hostname', 'username', 'password', 'profile_type']:
  1786. key = key.replace('_', '-')
  1787. try:
  1788. payload[key] = _set_value(value)
  1789. except salt.exceptions.CommandExecutionError:
  1790. return 'Error: Unable to Parse JSON data for parameter: {key}\n{value}'.format(key=key, value=value)
  1791. #put to REST
  1792. try:
  1793. response = bigip_session.put(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/profile/{type}/{name}'.format(type=profile_type, name=name), data=json.dumps(payload))
  1794. except requests.exceptions.ConnectionError as e:
  1795. return _load_connection_error(hostname, e)
  1796. return _load_response(response)
  1797. def delete_profile(hostname, username, password, profile_type, name):
  1798. '''
  1799. A function to connect to a bigip device and delete an existing profile.
  1800. hostname
  1801. The host/address of the bigip device
  1802. username
  1803. The iControl REST username
  1804. password
  1805. The iControl REST password
  1806. profile_type
  1807. The type of profile to delete
  1808. name
  1809. The name of the profile to delete
  1810. CLI Example::
  1811. salt '*' bigip.delete_profile bigip admin admin http my-http-profile
  1812. '''
  1813. #build sessions
  1814. bigip_session = _build_session(username, password)
  1815. #delete to REST
  1816. try:
  1817. response = bigip_session.delete(BIG_IP_URL_BASE.format(host=hostname)+'/ltm/profile/{type}/{name}'.format(type=profile_type, name=name))
  1818. except requests.exceptions.ConnectionError as e:
  1819. return _load_connection_error(hostname, e)
  1820. if _load_response(response) == '':
  1821. return True
  1822. else:
  1823. return _load_response(response)