Mini Shell
"""
An execution module which can manipulate an f5 bigip via iControl REST
:maturity: develop
:platform: f5_bigip_11.6
"""
import salt.exceptions
import salt.utils.json
try:
import requests
import requests.exceptions
HAS_LIBS = True
except ImportError:
HAS_LIBS = False
# Define the module's virtual name
__virtualname__ = "bigip"
def __virtual__():
"""
Only return if requests is installed
"""
if HAS_LIBS:
return __virtualname__
return (
False,
"The bigip execution module cannot be loaded: "
"python requests library not available.",
)
BIG_IP_URL_BASE = "https://{host}/mgmt/tm"
def _build_session(username, password, trans_label=None):
"""
Create a session to be used when connecting to iControl REST.
"""
bigip = requests.session()
bigip.auth = (username, password)
bigip.verify = True
bigip.headers.update({"Content-Type": "application/json"})
if trans_label:
# pull the trans id from the grain
trans_id = __salt__["grains.get"](f"bigip_f5_trans:{trans_label}")
if trans_id:
bigip.headers.update({"X-F5-REST-Coordination-Id": trans_id})
else:
bigip.headers.update({"X-F5-REST-Coordination-Id": None})
return bigip
def _load_response(response):
"""
Load the response from json data, return the dictionary or raw text
"""
try:
data = salt.utils.json.loads(response.text)
except ValueError:
data = response.text
ret = {"code": response.status_code, "content": data}
return ret
def _load_connection_error(hostname, error):
"""
Format and Return a connection error
"""
ret = {
"code": None,
"content": (
"Error: Unable to connect to the bigip device: {host}\n{error}".format(
host=hostname, error=error
)
),
}
return ret
def _loop_payload(params):
"""
Pass in a dictionary of parameters, loop through them and build a payload containing,
parameters who's values are not None.
"""
# construct the payload
payload = {}
# set the payload
for param, value in params.items():
if value is not None:
payload[param] = value
return payload
def _build_list(option_value, item_kind):
"""
pass in an option to check for a list of items, create a list of dictionary of items to set
for this option
"""
# specify profiles if provided
if option_value is not None:
items = []
# if user specified none, return an empty list
if option_value == "none":
return items
# was a list already passed in?
if not isinstance(option_value, list):
values = option_value.split(",")
else:
values = option_value
for value in values:
# sometimes the bigip just likes a plain ol list of items
if item_kind is None:
items.append(value)
# other times it's picky and likes key value pairs...
else:
items.append({"kind": item_kind, "name": value})
return items
return None
def _determine_toggles(payload, toggles):
"""
BigIP can't make up its mind if it likes yes / no or true or false.
Figure out what it likes to hear without confusing the user.
"""
for toggle, definition in toggles.items():
# did the user specify anything?
if definition["value"] is not None:
# test for yes_no toggle
if (
definition["value"] is True or definition["value"] == "yes"
) and definition["type"] == "yes_no":
payload[toggle] = "yes"
elif (
definition["value"] is False or definition["value"] == "no"
) and definition["type"] == "yes_no":
payload[toggle] = "no"
# test for true_false toggle
if (
definition["value"] is True or definition["value"] == "yes"
) and definition["type"] == "true_false":
payload[toggle] = True
elif (
definition["value"] is False or definition["value"] == "no"
) and definition["type"] == "true_false":
payload[toggle] = False
return payload
def _set_value(value):
"""
A function to detect if user is trying to pass a dictionary or list. parse it and return a
dictionary list or a string
"""
# don't continue if already an acceptable data-type
if isinstance(value, bool) or isinstance(value, dict) or isinstance(value, list):
return value
# check if json
if value.startswith("j{") and value.endswith("}j"):
value = value.replace("j{", "{")
value = value.replace("}j", "}")
try:
return salt.utils.json.loads(value)
except Exception: # pylint: disable=broad-except
raise salt.exceptions.CommandExecutionError
# detect list of dictionaries
if "|" in value and r"\|" not in value:
values = value.split("|")
items = []
for value in values:
items.append(_set_value(value))
return items
# parse out dictionary if detected
if ":" in value and r"\:" not in value:
options = {}
# split out pairs
key_pairs = value.split(",")
for key_pair in key_pairs:
k = key_pair.split(":")[0]
v = key_pair.split(":")[1]
options[k] = v
return options
# try making a list
elif "," in value and r"\," not in value:
value_items = value.split(",")
return value_items
# just return a string
else:
# remove escape chars if added
if r"\|" in value:
value = value.replace(r"\|", "|")
if r"\:" in value:
value = value.replace(r"\:", ":")
if r"\," in value:
value = value.replace(r"\,", ",")
return value
def start_transaction(hostname, username, password, label):
"""
A function to connect to a bigip device and start a new transaction.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
label
The name / alias for this transaction. The actual transaction
id will be stored within a grain called ``bigip_f5_trans:<label>``
CLI Example:
.. code-block:: bash
salt '*' bigip.start_transaction bigip admin admin my_transaction
"""
# build the session
bigip_session = _build_session(username, password)
payload = {}
# post to REST to get trans id
try:
response = bigip_session.post(
BIG_IP_URL_BASE.format(host=hostname) + "/transaction",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
# extract the trans_id
data = _load_response(response)
if data["code"] == 200:
trans_id = data["content"]["transId"]
__salt__["grains.setval"]("bigip_f5_trans", {label: trans_id})
return (
"Transaction: {trans_id} - has successfully been stored in the grain:"
" bigip_f5_trans:{label}".format(trans_id=trans_id, label=label)
)
else:
return data
def list_transaction(hostname, username, password, label):
"""
A function to connect to a bigip device and list an existing transaction.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
label
the label of this transaction stored within the grain:
``bigip_f5_trans:<label>``
CLI Example:
.. code-block:: bash
salt '*' bigip.list_transaction bigip admin admin my_transaction
"""
# build the session
bigip_session = _build_session(username, password)
# pull the trans id from the grain
trans_id = __salt__["grains.get"](f"bigip_f5_trans:{label}")
if trans_id:
# post to REST to get trans id
try:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname)
+ f"/transaction/{trans_id}/commands"
)
return _load_response(response)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
else:
return (
"Error: the label for this transaction was not defined as a grain. Begin a"
" new transaction using the bigip.start_transaction function"
)
def commit_transaction(hostname, username, password, label):
"""
A function to connect to a bigip device and commit an existing transaction.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
label
the label of this transaction stored within the grain:
``bigip_f5_trans:<label>``
CLI Example:
.. code-block:: bash
salt '*' bigip.commit_transaction bigip admin admin my_transaction
"""
# build the session
bigip_session = _build_session(username, password)
# pull the trans id from the grain
trans_id = __salt__["grains.get"](f"bigip_f5_trans:{label}")
if trans_id:
payload = {}
payload["state"] = "VALIDATING"
# patch to REST to get trans id
try:
response = bigip_session.patch(
BIG_IP_URL_BASE.format(host=hostname) + f"/transaction/{trans_id}",
data=salt.utils.json.dumps(payload),
)
return _load_response(response)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
else:
return (
"Error: the label for this transaction was not defined as a grain. Begin a"
" new transaction using the bigip.start_transaction function"
)
def delete_transaction(hostname, username, password, label):
"""
A function to connect to a bigip device and delete an existing transaction.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
label
The label of this transaction stored within the grain:
``bigip_f5_trans:<label>``
CLI Example:
.. code-block:: bash
salt '*' bigip.delete_transaction bigip admin admin my_transaction
"""
# build the session
bigip_session = _build_session(username, password)
# pull the trans id from the grain
trans_id = __salt__["grains.get"](f"bigip_f5_trans:{label}")
if trans_id:
# patch to REST to get trans id
try:
response = bigip_session.delete(
BIG_IP_URL_BASE.format(host=hostname) + f"/transaction/{trans_id}"
)
return _load_response(response)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
else:
return (
"Error: the label for this transaction was not defined as a grain. Begin a"
" new transaction using the bigip.start_transaction function"
)
def list_node(hostname, username, password, name=None, trans_label=None):
"""
A function to connect to a bigip device and list all nodes or a specific node.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the node to list. If no name is specified than all nodes
will be listed.
trans_label
The label of the transaction stored within the grain:
``bigip_f5_trans:<label>``
CLI Example:
.. code-block:: bash
salt '*' bigip.list_node bigip admin admin my-node
"""
# build sessions
bigip_session = _build_session(username, password, trans_label)
# get to REST
try:
if name:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/node/{name}"
)
else:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname) + "/ltm/node"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def create_node(hostname, username, password, name, address, trans_label=None):
"""
A function to connect to a bigip device and create a node.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the node
address
The address of the node
trans_label
The label of the transaction stored within the grain:
``bigip_f5_trans:<label>``
CLI Example:
.. code-block:: bash
salt '*' bigip.create_node bigip admin admin 10.1.1.2
"""
# build session
bigip_session = _build_session(username, password, trans_label)
# construct the payload
payload = {}
payload["name"] = name
payload["address"] = address
# post to REST
try:
response = bigip_session.post(
BIG_IP_URL_BASE.format(host=hostname) + "/ltm/node",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def modify_node(
hostname,
username,
password,
name,
connection_limit=None,
description=None,
dynamic_ratio=None,
logging=None,
monitor=None,
rate_limit=None,
ratio=None,
session=None,
state=None,
trans_label=None,
):
"""
A function to connect to a bigip device and modify an existing node.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the node to modify
connection_limit
[integer]
description
[string]
dynamic_ratio
[integer]
logging
[enabled | disabled]
monitor
[[name] | none | default]
rate_limit
[integer]
ratio
[integer]
session
[user-enabled | user-disabled]
state
[user-down | user-up ]
trans_label
The label of the transaction stored within the grain:
``bigip_f5_trans:<label>``
CLI Example:
.. code-block:: bash
salt '*' bigip.modify_node bigip admin admin 10.1.1.2 ratio=2 logging=enabled
"""
params = {
"connection-limit": connection_limit,
"description": description,
"dynamic-ratio": dynamic_ratio,
"logging": logging,
"monitor": monitor,
"rate-limit": rate_limit,
"ratio": ratio,
"session": session,
"state": state,
}
# build session
bigip_session = _build_session(username, password, trans_label)
# build payload
payload = _loop_payload(params)
payload["name"] = name
# put to REST
try:
response = bigip_session.put(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/node/{name}",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def delete_node(hostname, username, password, name, trans_label=None):
"""
A function to connect to a bigip device and delete a specific node.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the node which will be deleted.
trans_label
The label of the transaction stored within the grain:
``bigip_f5_trans:<label>``
CLI Example:
.. code-block:: bash
salt '*' bigip.delete_node bigip admin admin my-node
"""
# build session
bigip_session = _build_session(username, password, trans_label)
# delete to REST
try:
response = bigip_session.delete(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/node/{name}"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
if _load_response(response) == "":
return True
else:
return _load_response(response)
def list_pool(hostname, username, password, name=None):
"""
A function to connect to a bigip device and list all pools or a specific pool.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the pool to list. If no name is specified then all pools
will be listed.
CLI Example:
.. code-block:: bash
salt '*' bigip.list_pool bigip admin admin my-pool
"""
# build sessions
bigip_session = _build_session(username, password)
# get to REST
try:
if name:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname)
+ f"/ltm/pool/{name}/?expandSubcollections=true"
)
else:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname) + "/ltm/pool"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def create_pool(
hostname,
username,
password,
name,
members=None,
allow_nat=None,
allow_snat=None,
description=None,
gateway_failsafe_device=None,
ignore_persisted_weight=None,
ip_tos_to_client=None,
ip_tos_to_server=None,
link_qos_to_client=None,
link_qos_to_server=None,
load_balancing_mode=None,
min_active_members=None,
min_up_members=None,
min_up_members_action=None,
min_up_members_checking=None,
monitor=None,
profiles=None,
queue_depth_limit=None,
queue_on_connection_limit=None,
queue_time_limit=None,
reselect_tries=None,
service_down_action=None,
slow_ramp_time=None,
):
"""
A function to connect to a bigip device and create a pool.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the pool to create.
members
List of comma delimited pool members to add to the pool.
i.e. 10.1.1.1:80,10.1.1.2:80,10.1.1.3:80
allow_nat
[yes | no]
allow_snat
[yes | no]
description
[string]
gateway_failsafe_device
[string]
ignore_persisted_weight
[enabled | disabled]
ip_tos_to_client
[pass-through | [integer]]
ip_tos_to_server
[pass-through | [integer]]
link_qos_to_client
[pass-through | [integer]]
link_qos_to_server
[pass-through | [integer]]
load_balancing_mode
[dynamic-ratio-member | dynamic-ratio-node |
fastest-app-response | fastest-node |
least-connections-members |
least-connections-node |
least-sessions |
observed-member | observed-node |
predictive-member | predictive-node |
ratio-least-connections-member |
ratio-least-connections-node |
ratio-member | ratio-node | ratio-session |
round-robin | weighted-least-connections-member |
weighted-least-connections-node]
min_active_members
[integer]
min_up_members
[integer]
min_up_members_action
[failover | reboot | restart-all]
min_up_members_checking
[enabled | disabled]
monitor
[name]
profiles
[none | profile_name]
queue_depth_limit
[integer]
queue_on_connection_limit
[enabled | disabled]
queue_time_limit
[integer]
reselect_tries
[integer]
service_down_action
[drop | none | reselect | reset]
slow_ramp_time
[integer]
CLI Example:
.. code-block:: bash
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
"""
params = {
"description": description,
"gateway-failsafe-device": gateway_failsafe_device,
"ignore-persisted-weight": ignore_persisted_weight,
"ip-tos-to-client": ip_tos_to_client,
"ip-tos-to-server": ip_tos_to_server,
"link-qos-to-client": link_qos_to_client,
"link-qos-to-server": link_qos_to_server,
"load-balancing-mode": load_balancing_mode,
"min-active-members": min_active_members,
"min-up-members": min_up_members,
"min-up-members-action": min_up_members_action,
"min-up-members-checking": min_up_members_checking,
"monitor": monitor,
"profiles": profiles,
"queue-on-connection-limit": queue_on_connection_limit,
"queue-depth-limit": queue_depth_limit,
"queue-time-limit": queue_time_limit,
"reselect-tries": reselect_tries,
"service-down-action": service_down_action,
"slow-ramp-time": slow_ramp_time,
}
# some options take yes no others take true false. Figure out when to use which without
# confusing the end user
toggles = {
"allow-nat": {"type": "yes_no", "value": allow_nat},
"allow-snat": {"type": "yes_no", "value": allow_snat},
}
# build payload
payload = _loop_payload(params)
payload["name"] = name
# determine toggles
payload = _determine_toggles(payload, toggles)
# specify members if provided
if members is not None:
payload["members"] = _build_list(members, "ltm:pool:members")
# build session
bigip_session = _build_session(username, password)
# post to REST
try:
response = bigip_session.post(
BIG_IP_URL_BASE.format(host=hostname) + "/ltm/pool",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def modify_pool(
hostname,
username,
password,
name,
allow_nat=None,
allow_snat=None,
description=None,
gateway_failsafe_device=None,
ignore_persisted_weight=None,
ip_tos_to_client=None,
ip_tos_to_server=None,
link_qos_to_client=None,
link_qos_to_server=None,
load_balancing_mode=None,
min_active_members=None,
min_up_members=None,
min_up_members_action=None,
min_up_members_checking=None,
monitor=None,
profiles=None,
queue_depth_limit=None,
queue_on_connection_limit=None,
queue_time_limit=None,
reselect_tries=None,
service_down_action=None,
slow_ramp_time=None,
):
"""
A function to connect to a bigip device and modify an existing pool.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the pool to modify.
allow_nat
[yes | no]
allow_snat
[yes | no]
description
[string]
gateway_failsafe_device
[string]
ignore_persisted_weight
[yes | no]
ip_tos_to_client
[pass-through | [integer]]
ip_tos_to_server
[pass-through | [integer]]
link_qos_to_client
[pass-through | [integer]]
link_qos_to_server
[pass-through | [integer]]
load_balancing_mode
[dynamic-ratio-member | dynamic-ratio-node |
fastest-app-response | fastest-node |
least-connections-members |
least-connections-node |
least-sessions |
observed-member | observed-node |
predictive-member | predictive-node |
ratio-least-connections-member |
ratio-least-connections-node |
ratio-member | ratio-node | ratio-session |
round-robin | weighted-least-connections-member |
weighted-least-connections-node]
min_active_members
[integer]
min_up_members
[integer]
min_up_members_action
[failover | reboot | restart-all]
min_up_members_checking
[enabled | disabled]
monitor
[name]
profiles
[none | profile_name]
queue_on_connection_limit
[enabled | disabled]
queue_depth_limit
[integer]
queue_time_limit
[integer]
reselect_tries
[integer]
service_down_action
[drop | none | reselect | reset]
slow_ramp_time
[integer]
CLI Example:
.. code-block:: bash
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
"""
params = {
"description": description,
"gateway-failsafe-device": gateway_failsafe_device,
"ignore-persisted-weight": ignore_persisted_weight,
"ip-tos-to-client": ip_tos_to_client,
"ip-tos-to-server": ip_tos_to_server,
"link-qos-to-client": link_qos_to_client,
"link-qos-to-server": link_qos_to_server,
"load-balancing-mode": load_balancing_mode,
"min-active-members": min_active_members,
"min-up-members": min_up_members,
"min-up_members-action": min_up_members_action,
"min-up-members-checking": min_up_members_checking,
"monitor": monitor,
"profiles": profiles,
"queue-on-connection-limit": queue_on_connection_limit,
"queue-depth-limit": queue_depth_limit,
"queue-time-limit": queue_time_limit,
"reselect-tries": reselect_tries,
"service-down-action": service_down_action,
"slow-ramp-time": slow_ramp_time,
}
# some options take yes no others take true false. Figure out when to use which without
# confusing the end user
toggles = {
"allow-nat": {"type": "yes_no", "value": allow_nat},
"allow-snat": {"type": "yes_no", "value": allow_snat},
}
# build payload
payload = _loop_payload(params)
payload["name"] = name
# determine toggles
payload = _determine_toggles(payload, toggles)
# build session
bigip_session = _build_session(username, password)
# post to REST
try:
response = bigip_session.put(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def delete_pool(hostname, username, password, name):
"""
A function to connect to a bigip device and delete a specific pool.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the pool which will be deleted
CLI Example
.. code-block:: bash
salt '*' bigip.delete_node bigip admin admin my-pool
"""
# build session
bigip_session = _build_session(username, password)
# delete to REST
try:
response = bigip_session.delete(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
if _load_response(response) == "":
return True
else:
return _load_response(response)
def replace_pool_members(hostname, username, password, name, members):
"""
A function to connect to a bigip device and replace members of an existing pool with new members.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the pool to modify
members
List of comma delimited pool members to replace existing members with.
i.e. 10.1.1.1:80,10.1.1.2:80,10.1.1.3:80
CLI Example:
.. code-block:: bash
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
"""
payload = {}
payload["name"] = name
# specify members if provided
if members is not None:
if isinstance(members, str):
members = members.split(",")
pool_members = []
for member in members:
# check to see if already a dictionary ( for states)
if isinstance(member, dict):
# check for state alternative name 'member_state', replace with state
if "member_state" in member.keys():
member["state"] = member.pop("member_state")
# replace underscore with dash
for key in member:
new_key = key.replace("_", "-")
member[new_key] = member.pop(key)
pool_members.append(member)
# parse string passed via execution command (for executions)
else:
pool_members.append({"name": member, "address": member.split(":")[0]})
payload["members"] = pool_members
# build session
bigip_session = _build_session(username, password)
# put to REST
try:
response = bigip_session.put(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def add_pool_member(hostname, username, password, name, member):
"""
A function to connect to a bigip device and add a new member to an existing pool.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the pool to modify
member
The name of the member to add
i.e. 10.1.1.2:80
CLI Example:
.. code-block:: bash
salt '*' bigip.add_pool_members bigip admin admin my-pool 10.2.2.1:80
"""
# for states
if isinstance(member, dict):
# check for state alternative name 'member_state', replace with state
if "member_state" in member.keys():
member["state"] = member.pop("member_state")
# replace underscore with dash
for key in member:
new_key = key.replace("_", "-")
member[new_key] = member.pop(key)
payload = member
# for execution
else:
payload = {"name": member, "address": member.split(":")[0]}
# build session
bigip_session = _build_session(username, password)
# post to REST
try:
response = bigip_session.post(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}/members",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def modify_pool_member(
hostname,
username,
password,
name,
member,
connection_limit=None,
description=None,
dynamic_ratio=None,
inherit_profile=None,
logging=None,
monitor=None,
priority_group=None,
profiles=None,
rate_limit=None,
ratio=None,
session=None,
state=None,
):
"""
A function to connect to a bigip device and modify an existing member of a pool.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the pool to modify
member
The name of the member to modify i.e. 10.1.1.2:80
connection_limit
[integer]
description
[string]
dynamic_ratio
[integer]
inherit_profile
[enabled | disabled]
logging
[enabled | disabled]
monitor
[name]
priority_group
[integer]
profiles
[none | profile_name]
rate_limit
[integer]
ratio
[integer]
session
[user-enabled | user-disabled]
state
[ user-up | user-down ]
CLI Example:
.. code-block:: bash
salt '*' bigip.modify_pool_member bigip admin admin my-pool 10.2.2.1:80 state=use-down session=user-disabled
"""
params = {
"connection-limit": connection_limit,
"description": description,
"dynamic-ratio": dynamic_ratio,
"inherit-profile": inherit_profile,
"logging": logging,
"monitor": monitor,
"priority-group": priority_group,
"profiles": profiles,
"rate-limit": rate_limit,
"ratio": ratio,
"session": session,
"state": state,
}
# build session
bigip_session = _build_session(username, password)
# build payload
payload = _loop_payload(params)
# put to REST
try:
response = bigip_session.put(
BIG_IP_URL_BASE.format(host=hostname)
+ f"/ltm/pool/{name}/members/{member}",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def delete_pool_member(hostname, username, password, name, member):
"""
A function to connect to a bigip device and delete a specific pool.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the pool to modify
member
The name of the pool member to delete
CLI Example:
.. code-block:: bash
salt '*' bigip.delete_pool_member bigip admin admin my-pool 10.2.2.2:80
"""
# build session
bigip_session = _build_session(username, password)
# delete to REST
try:
response = bigip_session.delete(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/pool/{name}/members/{member}"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
if _load_response(response) == "":
return True
else:
return _load_response(response)
def list_virtual(hostname, username, password, name=None):
"""
A function to connect to a bigip device and list all virtuals or a specific virtual.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the virtual to list. If no name is specified than all
virtuals will be listed.
CLI Example:
.. code-block:: bash
salt '*' bigip.list_virtual bigip admin admin my-virtual
"""
# build sessions
bigip_session = _build_session(username, password)
# get to REST
try:
if name:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname)
+ f"/ltm/virtual/{name}/?expandSubcollections=true"
)
else:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname) + "/ltm/virtual"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def create_virtual(
hostname,
username,
password,
name,
destination,
pool=None,
address_status=None,
auto_lasthop=None,
bwc_policy=None,
cmp_enabled=None,
connection_limit=None,
dhcp_relay=None,
description=None,
fallback_persistence=None,
flow_eviction_policy=None,
gtm_score=None,
ip_forward=None,
ip_protocol=None,
internal=None,
twelve_forward=None,
last_hop_pool=None,
mask=None,
mirror=None,
nat64=None,
persist=None,
profiles=None,
policies=None,
rate_class=None,
rate_limit=None,
rate_limit_mode=None,
rate_limit_dst=None,
rate_limit_src=None,
rules=None,
related_rules=None,
reject=None,
source=None,
source_address_translation=None,
source_port=None,
state=None,
traffic_classes=None,
translate_address=None,
translate_port=None,
vlans=None,
):
r"""
A function to connect to a bigip device and create a virtual server.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the virtual to create
destination
[ [virtual_address_name:port] | [ipv4:port] | [ipv6.port] ]
pool
[ [pool_name] | none]
address_status
[yes | no]
auto_lasthop
[default | enabled | disabled ]
bwc_policy
[none] | string]
cmp_enabled
[yes | no]
dhcp_relay
[yes | no]
connection_limit
[integer]
description
[string]
state
[disabled | enabled]
fallback_persistence
[none | [profile name] ]
flow_eviction_policy
[none | [eviction policy name] ]
gtm_score
[integer]
ip_forward
[yes | no]
ip_protocol
[any | protocol]
internal
[yes | no]
twelve_forward
(12-forward)
[yes | no]
last_hop-pool
[ [pool_name] | none]
mask
{ [ipv4] | [ipv6] }
mirror
{ [disabled | enabled | none] }
nat64
[enabled | disabled]
persist
[none | profile1,profile2,profile3 ... ]
profiles
[none | default | profile1,profile2,profile3 ... ]
policies
[none | default | policy1,policy2,policy3 ... ]
rate_class
[name]
rate_limit
[integer]
rate_limit_mode
[destination | object | object-destination |
object-source | object-source-destination |
source | source-destination]
rate_limit_dst
[integer]
rate_limitçsrc
[integer]
rules
[none | [rule_one,rule_two ...] ]
related_rules
[none | [rule_one,rule_two ...] ]
reject
[yes | no]
source
{ [ipv4[/prefixlen]] | [ipv6[/prefixlen]] }
source_address_translation
[none | snat:pool_name | lsn | automap ]
source_port
[change | preserve | preserve-strict]
state
[enabled | disabled]
traffic_classes
[none | default | class_one,class_two ... ]
translate_address
[enabled | disabled]
translate_port
[enabled | disabled]
vlans
[none | default | [enabled|disabled]:vlan1,vlan2,vlan3 ... ]
CLI Example:
.. code-block:: bash
salt '*' bigip.create_virtual bigip admin admin my-virtual-3 26.2.2.5:80 \
pool=my-http-pool-http profiles=http,tcp
salt '*' bigip.create_virtual bigip admin admin my-virtual-3 43.2.2.5:80 \
pool=test-http-pool-http profiles=http,websecurity persist=cookie,hash \
policies=asm_auto_l7_policy__http-virtual \
rules=_sys_APM_ExchangeSupport_helper,_sys_https_redirect \
related_rules=_sys_APM_activesync,_sys_APM_ExchangeSupport_helper \
source_address_translation=snat:my-snat-pool \
translate_address=enabled translate_port=enabled \
traffic_classes=my-class,other-class \
vlans=enabled:external,internal
"""
params = {
"pool": pool,
"auto-lasthop": auto_lasthop,
"bwc-policy": bwc_policy,
"connection-limit": connection_limit,
"description": description,
"fallback-persistence": fallback_persistence,
"flow-eviction-policy": flow_eviction_policy,
"gtm-score": gtm_score,
"ip-protocol": ip_protocol,
"last-hop-pool": last_hop_pool,
"mask": mask,
"mirror": mirror,
"nat64": nat64,
"persist": persist,
"rate-class": rate_class,
"rate-limit": rate_limit,
"rate-limit-mode": rate_limit_mode,
"rate-limit-dst": rate_limit_dst,
"rate-limit-src": rate_limit_src,
"source": source,
"source-port": source_port,
"translate-address": translate_address,
"translate-port": translate_port,
}
# some options take yes no others take true false. Figure out when to use which without
# confusing the end user
toggles = {
"address-status": {"type": "yes_no", "value": address_status},
"cmp-enabled": {"type": "yes_no", "value": cmp_enabled},
"dhcp-relay": {"type": "true_false", "value": dhcp_relay},
"reject": {"type": "true_false", "value": reject},
"12-forward": {"type": "true_false", "value": twelve_forward},
"internal": {"type": "true_false", "value": internal},
"ip-forward": {"type": "true_false", "value": ip_forward},
}
# build session
bigip_session = _build_session(username, password)
# build payload
payload = _loop_payload(params)
payload["name"] = name
payload["destination"] = destination
# determine toggles
payload = _determine_toggles(payload, toggles)
# specify profiles if provided
if profiles is not None:
payload["profiles"] = _build_list(profiles, "ltm:virtual:profile")
# specify persist if provided
if persist is not None:
payload["persist"] = _build_list(persist, "ltm:virtual:persist")
# specify policies if provided
if policies is not None:
payload["policies"] = _build_list(policies, "ltm:virtual:policy")
# specify rules if provided
if rules is not None:
payload["rules"] = _build_list(rules, None)
# specify related-rules if provided
if related_rules is not None:
payload["related-rules"] = _build_list(related_rules, None)
# handle source-address-translation
if source_address_translation is not None:
# check to see if this is already a dictionary first
if isinstance(source_address_translation, dict):
payload["source-address-translation"] = source_address_translation
elif source_address_translation == "none":
payload["source-address-translation"] = {"pool": "none", "type": "none"}
elif source_address_translation == "automap":
payload["source-address-translation"] = {"pool": "none", "type": "automap"}
elif source_address_translation == "lsn":
payload["source-address-translation"] = {"pool": "none", "type": "lsn"}
elif source_address_translation.startswith("snat"):
snat_pool = source_address_translation.split(":")[1]
payload["source-address-translation"] = {"pool": snat_pool, "type": "snat"}
# specify related-rules if provided
if traffic_classes is not None:
payload["traffic-classes"] = _build_list(traffic_classes, None)
# handle vlans
if vlans is not None:
# ceck to see if vlans is a dictionary (used when state makes use of function)
if isinstance(vlans, dict):
try:
payload["vlans"] = vlans["vlan_ids"]
if vlans["enabled"]:
payload["vlans-enabled"] = True
elif vlans["disabled"]:
payload["vlans-disabled"] = True
except Exception: # pylint: disable=broad-except
return (
"Error: Unable to Parse vlans dictionary: \n\tvlans={vlans}".format(
vlans=vlans
)
)
elif vlans == "none":
payload["vlans"] = "none"
elif vlans == "default":
payload["vlans"] = "default"
elif isinstance(vlans, str) and (
vlans.startswith("enabled") or vlans.startswith("disabled")
):
try:
vlans_setting = vlans.split(":")[0]
payload["vlans"] = vlans.split(":")[1].split(",")
if vlans_setting == "disabled":
payload["vlans-disabled"] = True
elif vlans_setting == "enabled":
payload["vlans-enabled"] = True
except Exception: # pylint: disable=broad-except
return "Error: Unable to Parse vlans option: \n\tvlans={vlans}".format(
vlans=vlans
)
else:
return "Error: vlans must be a dictionary or string."
# determine state
if state is not None:
if state == "enabled":
payload["enabled"] = True
elif state == "disabled":
payload["disabled"] = True
# post to REST
try:
response = bigip_session.post(
BIG_IP_URL_BASE.format(host=hostname) + "/ltm/virtual",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def modify_virtual(
hostname,
username,
password,
name,
destination=None,
pool=None,
address_status=None,
auto_lasthop=None,
bwc_policy=None,
cmp_enabled=None,
connection_limit=None,
dhcp_relay=None,
description=None,
fallback_persistence=None,
flow_eviction_policy=None,
gtm_score=None,
ip_forward=None,
ip_protocol=None,
internal=None,
twelve_forward=None,
last_hop_pool=None,
mask=None,
mirror=None,
nat64=None,
persist=None,
profiles=None,
policies=None,
rate_class=None,
rate_limit=None,
rate_limit_mode=None,
rate_limit_dst=None,
rate_limit_src=None,
rules=None,
related_rules=None,
reject=None,
source=None,
source_address_translation=None,
source_port=None,
state=None,
traffic_classes=None,
translate_address=None,
translate_port=None,
vlans=None,
):
"""
A function to connect to a bigip device and modify an existing virtual server.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the virtual to modify
destination
[ [virtual_address_name:port] | [ipv4:port] | [ipv6.port] ]
pool
[ [pool_name] | none]
address_status
[yes | no]
auto_lasthop
[default | enabled | disabled ]
bwc_policy
[none] | string]
cmp_enabled
[yes | no]
dhcp_relay
[yes | no}
connection_limit
[integer]
description
[string]
state
[disabled | enabled]
fallback_persistence
[none | [profile name] ]
flow_eviction_policy
[none | [eviction policy name] ]
gtm_score
[integer]
ip_forward
[yes | no]
ip_protocol
[any | protocol]
internal
[yes | no]
twelve_forward
(12-forward)
[yes | no]
last_hop-pool
[ [pool_name] | none]
mask
{ [ipv4] | [ipv6] }
mirror
{ [disabled | enabled | none] }
nat64
[enabled | disabled]
persist
[none | profile1,profile2,profile3 ... ]
profiles
[none | default | profile1,profile2,profile3 ... ]
policies
[none | default | policy1,policy2,policy3 ... ]
rate_class
[name]
rate_limit
[integer]
rate_limitr_mode
[destination | object | object-destination |
object-source | object-source-destination |
source | source-destination]
rate_limit_dst
[integer]
rate_limit_src
[integer]
rules
[none | [rule_one,rule_two ...] ]
related_rules
[none | [rule_one,rule_two ...] ]
reject
[yes | no]
source
{ [ipv4[/prefixlen]] | [ipv6[/prefixlen]] }
source_address_translation
[none | snat:pool_name | lsn | automap ]
source_port
[change | preserve | preserve-strict]
state
[enabled | disable]
traffic_classes
[none | default | class_one,class_two ... ]
translate_address
[enabled | disabled]
translate_port
[enabled | disabled]
vlans
[none | default | [enabled|disabled]:vlan1,vlan2,vlan3 ... ]
CLI Example:
.. code-block:: bash
salt '*' bigip.modify_virtual bigip admin admin my-virtual source_address_translation=none
salt '*' bigip.modify_virtual bigip admin admin my-virtual rules=my-rule,my-other-rule
"""
params = {
"destination": destination,
"pool": pool,
"auto-lasthop": auto_lasthop,
"bwc-policy": bwc_policy,
"connection-limit": connection_limit,
"description": description,
"fallback-persistence": fallback_persistence,
"flow-eviction-policy": flow_eviction_policy,
"gtm-score": gtm_score,
"ip-protocol": ip_protocol,
"last-hop-pool": last_hop_pool,
"mask": mask,
"mirror": mirror,
"nat64": nat64,
"persist": persist,
"rate-class": rate_class,
"rate-limit": rate_limit,
"rate-limit-mode": rate_limit_mode,
"rate-limit-dst": rate_limit_dst,
"rate-limit-src": rate_limit_src,
"source": source,
"source-port": source_port,
"translate-address": translate_address,
"translate-port": translate_port,
}
# some options take yes no others take true false. Figure out when to use which without
# confusing the end user
toggles = {
"address-status": {"type": "yes_no", "value": address_status},
"cmp-enabled": {"type": "yes_no", "value": cmp_enabled},
"dhcp-relay": {"type": "true_false", "value": dhcp_relay},
"reject": {"type": "true_false", "value": reject},
"12-forward": {"type": "true_false", "value": twelve_forward},
"internal": {"type": "true_false", "value": internal},
"ip-forward": {"type": "true_false", "value": ip_forward},
}
# build session
bigip_session = _build_session(username, password)
# build payload
payload = _loop_payload(params)
payload["name"] = name
# determine toggles
payload = _determine_toggles(payload, toggles)
# specify profiles if provided
if profiles is not None:
payload["profiles"] = _build_list(profiles, "ltm:virtual:profile")
# specify persist if provided
if persist is not None:
payload["persist"] = _build_list(persist, "ltm:virtual:persist")
# specify policies if provided
if policies is not None:
payload["policies"] = _build_list(policies, "ltm:virtual:policy")
# specify rules if provided
if rules is not None:
payload["rules"] = _build_list(rules, None)
# specify related-rules if provided
if related_rules is not None:
payload["related-rules"] = _build_list(related_rules, None)
# handle source-address-translation
if source_address_translation is not None:
if source_address_translation == "none":
payload["source-address-translation"] = {"pool": "none", "type": "none"}
elif source_address_translation == "automap":
payload["source-address-translation"] = {"pool": "none", "type": "automap"}
elif source_address_translation == "lsn":
payload["source-address-translation"] = {"pool": "none", "type": "lsn"}
elif source_address_translation.startswith("snat"):
snat_pool = source_address_translation.split(":")[1]
payload["source-address-translation"] = {"pool": snat_pool, "type": "snat"}
# specify related-rules if provided
if traffic_classes is not None:
payload["traffic-classes"] = _build_list(traffic_classes, None)
# handle vlans
if vlans is not None:
# ceck to see if vlans is a dictionary (used when state makes use of function)
if isinstance(vlans, dict):
try:
payload["vlans"] = vlans["vlan_ids"]
if vlans["enabled"]:
payload["vlans-enabled"] = True
elif vlans["disabled"]:
payload["vlans-disabled"] = True
except Exception: # pylint: disable=broad-except
return (
"Error: Unable to Parse vlans dictionary: \n\tvlans={vlans}".format(
vlans=vlans
)
)
elif vlans == "none":
payload["vlans"] = "none"
elif vlans == "default":
payload["vlans"] = "default"
elif vlans.startswith("enabled") or vlans.startswith("disabled"):
try:
vlans_setting = vlans.split(":")[0]
payload["vlans"] = vlans.split(":")[1].split(",")
if vlans_setting == "disabled":
payload["vlans-disabled"] = True
elif vlans_setting == "enabled":
payload["vlans-enabled"] = True
except Exception: # pylint: disable=broad-except
return "Error: Unable to Parse vlans option: \n\tvlans={vlans}".format(
vlans=vlans
)
# determine state
if state is not None:
if state == "enabled":
payload["enabled"] = True
elif state == "disabled":
payload["disabled"] = True
# put to REST
try:
response = bigip_session.put(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/virtual/{name}",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def delete_virtual(hostname, username, password, name):
"""
A function to connect to a bigip device and delete a specific virtual.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
name
The name of the virtual to delete
CLI Example:
.. code-block:: bash
salt '*' bigip.delete_virtual bigip admin admin my-virtual
"""
# build session
bigip_session = _build_session(username, password)
# delete to REST
try:
response = bigip_session.delete(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/virtual/{name}"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
if _load_response(response) == "":
return True
else:
return _load_response(response)
def list_monitor(
hostname,
username,
password,
monitor_type,
name=None,
):
"""
A function to connect to a bigip device and list an existing monitor. If no name is provided than all
monitors of the specified type will be listed.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
monitor_type
The type of monitor(s) to list
name
The name of the monitor to list
CLI Example:
.. code-block:: bash
salt '*' bigip.list_monitor bigip admin admin http my-http-monitor
"""
# build sessions
bigip_session = _build_session(username, password)
# get to REST
try:
if name:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname)
+ "/ltm/monitor/{type}/{name}?expandSubcollections=true".format(
type=monitor_type, name=name
)
)
else:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/monitor/{monitor_type}"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def create_monitor(hostname, username, password, monitor_type, name, **kwargs):
"""
A function to connect to a bigip device and create a monitor.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
monitor_type
The type of monitor to create
name
The name of the monitor to create
kwargs
Consult F5 BIGIP user guide for specific options for each monitor type.
Typically, tmsh arg names are used.
CLI Example:
.. code-block:: bash
salt '*' bigip.create_monitor bigip admin admin http my-http-monitor timeout=10 interval=5
"""
# build session
bigip_session = _build_session(username, password)
# construct the payload
payload = {}
payload["name"] = name
# there's a ton of different monitors and a ton of options for each type of monitor.
# this logic relies that the end user knows which options are meant for which monitor types
for key, value in kwargs.items():
if not key.startswith("__"):
if key not in ["hostname", "username", "password", "type"]:
key = key.replace("_", "-")
payload[key] = value
# post to REST
try:
response = bigip_session.post(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/monitor/{monitor_type}",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def modify_monitor(hostname, username, password, monitor_type, name, **kwargs):
"""
A function to connect to a bigip device and modify an existing monitor.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
monitor_type
The type of monitor to modify
name
The name of the monitor to modify
kwargs
Consult F5 BIGIP user guide for specific options for each monitor type.
Typically, tmsh arg names are used.
CLI Example:
.. code-block:: bash
salt '*' bigip.modify_monitor bigip admin admin http my-http-monitor timout=16 interval=6
"""
# build session
bigip_session = _build_session(username, password)
# construct the payload
payload = {}
# there's a ton of different monitors and a ton of options for each type of monitor.
# this logic relies that the end user knows which options are meant for which monitor types
for key, value in kwargs.items():
if not key.startswith("__"):
if key not in ["hostname", "username", "password", "type", "name"]:
key = key.replace("_", "-")
payload[key] = value
# put to REST
try:
response = bigip_session.put(
BIG_IP_URL_BASE.format(host=hostname)
+ f"/ltm/monitor/{monitor_type}/{name}",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def delete_monitor(hostname, username, password, monitor_type, name):
"""
A function to connect to a bigip device and delete an existing monitor.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
monitor_type
The type of monitor to delete
name
The name of the monitor to delete
CLI Example:
.. code-block:: bash
salt '*' bigip.delete_monitor bigip admin admin http my-http-monitor
"""
# build sessions
bigip_session = _build_session(username, password)
# delete to REST
try:
response = bigip_session.delete(
BIG_IP_URL_BASE.format(host=hostname)
+ f"/ltm/monitor/{monitor_type}/{name}"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
if _load_response(response) == "":
return True
else:
return _load_response(response)
def list_profile(
hostname,
username,
password,
profile_type,
name=None,
):
"""
A function to connect to a bigip device and list an existing profile. If no name is provided than all
profiles of the specified type will be listed.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
profile_type
The type of profile(s) to list
name
The name of the profile to list
CLI Example:
.. code-block:: bash
salt '*' bigip.list_profile bigip admin admin http my-http-profile
"""
# build sessions
bigip_session = _build_session(username, password)
# get to REST
try:
if name:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname)
+ "/ltm/profile/{type}/{name}?expandSubcollections=true".format(
type=profile_type, name=name
)
)
else:
response = bigip_session.get(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/profile/{profile_type}"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def create_profile(hostname, username, password, profile_type, name, **kwargs):
r"""
A function to connect to a bigip device and create a profile.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
profile_type
The type of profile to create
name
The name of the profile to create
kwargs
``[ arg=val ] ... [arg=key1:val1,key2:val2] ...``
Consult F5 BIGIP user guide for specific options for each monitor type.
Typically, tmsh arg names are used.
Creating Complex Args
Profiles can get pretty complicated in terms of the amount of possible
config options. Use the following shorthand to create complex arguments such
as lists, dictionaries, and lists of dictionaries. An option is also
provided to pass raw json as well.
lists ``[i,i,i]``:
``param='item1,item2,item3'``
Dictionary ``[k:v,k:v,k,v]``:
``param='key-1:val-1,key-2:val2,key-3:va-3'``
List of Dictionaries ``[k:v,k:v|k:v,k:v|k:v,k:v]``:
``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'``
JSON: ``'j{ ... }j'``:
``cert-key-chain='j{ "default": { "cert": "default.crt", "chain": "default.crt", "key": "default.key" } }j'``
Escaping Delimiters:
Use ``\,`` or ``\:`` or ``\|`` to escape characters which shouldn't
be treated as delimiters i.e. ``ciphers='DEFAULT\:!SSLv3'``
CLI Example:
.. code-block:: bash
salt '*' bigip.create_profile bigip admin admin http my-http-profile defaultsFrom='/Common/http'
salt '*' bigip.create_profile bigip admin admin http my-http-profile defaultsFrom='/Common/http' \
enforcement=maxHeaderCount:3200,maxRequests:10
"""
# build session
bigip_session = _build_session(username, password)
# construct the payload
payload = {}
payload["name"] = name
# there's a ton of different profiles and a ton of options for each type of profile.
# this logic relies that the end user knows which options are meant for which profile types
for key, value in kwargs.items():
if not key.startswith("__"):
if key not in ["hostname", "username", "password", "profile_type"]:
key = key.replace("_", "-")
try:
payload[key] = _set_value(value)
except salt.exceptions.CommandExecutionError:
return "Error: Unable to Parse JSON data for parameter: {key}\n{value}".format(
key=key, value=value
)
# post to REST
try:
response = bigip_session.post(
BIG_IP_URL_BASE.format(host=hostname) + f"/ltm/profile/{profile_type}",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def modify_profile(hostname, username, password, profile_type, name, **kwargs):
r"""
A function to connect to a bigip device and create a profile.
A function to connect to a bigip device and create a profile.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
profile_type
The type of profile to create
name
The name of the profile to create
kwargs
``[ arg=val ] ... [arg=key1:val1,key2:val2] ...``
Consult F5 BIGIP user guide for specific options for each monitor type.
Typically, tmsh arg names are used.
Creating Complex Args
Profiles can get pretty complicated in terms of the amount of possible
config options. Use the following shorthand to create complex arguments such
as lists, dictionaries, and lists of dictionaries. An option is also
provided to pass raw json as well.
lists ``[i,i,i]``:
``param='item1,item2,item3'``
Dictionary ``[k:v,k:v,k,v]``:
``param='key-1:val-1,key-2:val2,key-3:va-3'``
List of Dictionaries ``[k:v,k:v|k:v,k:v|k:v,k:v]``:
``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'``
JSON: ``'j{ ... }j'``:
``cert-key-chain='j{ "default": { "cert": "default.crt", "chain": "default.crt", "key": "default.key" } }j'``
Escaping Delimiters:
Use ``\,`` or ``\:`` or ``\|`` to escape characters which shouldn't
be treated as delimiters i.e. ``ciphers='DEFAULT\:!SSLv3'``
CLI Example:
.. code-block:: bash
salt '*' bigip.modify_profile bigip admin admin http my-http-profile defaultsFrom='/Common/http'
salt '*' bigip.modify_profile bigip admin admin http my-http-profile defaultsFrom='/Common/http' \
enforcement=maxHeaderCount:3200,maxRequests:10
salt '*' bigip.modify_profile bigip admin admin client-ssl my-client-ssl-1 retainCertificate=false \
ciphers='DEFAULT\:!SSLv3'
cert_key_chain='j{ "default": { "cert": "default.crt", "chain": "default.crt", "key": "default.key" } }j'
"""
# build session
bigip_session = _build_session(username, password)
# construct the payload
payload = {}
payload["name"] = name
# there's a ton of different profiles and a ton of options for each type of profile.
# this logic relies that the end user knows which options are meant for which profile types
for key, value in kwargs.items():
if not key.startswith("__"):
if key not in ["hostname", "username", "password", "profile_type"]:
key = key.replace("_", "-")
try:
payload[key] = _set_value(value)
except salt.exceptions.CommandExecutionError:
return "Error: Unable to Parse JSON data for parameter: {key}\n{value}".format(
key=key, value=value
)
# put to REST
try:
response = bigip_session.put(
BIG_IP_URL_BASE.format(host=hostname)
+ f"/ltm/profile/{profile_type}/{name}",
data=salt.utils.json.dumps(payload),
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
return _load_response(response)
def delete_profile(hostname, username, password, profile_type, name):
"""
A function to connect to a bigip device and delete an existing profile.
hostname
The host/address of the bigip device
username
The iControl REST username
password
The iControl REST password
profile_type
The type of profile to delete
name
The name of the profile to delete
CLI Example:
.. code-block:: bash
salt '*' bigip.delete_profile bigip admin admin http my-http-profile
"""
# build sessions
bigip_session = _build_session(username, password)
# delete to REST
try:
response = bigip_session.delete(
BIG_IP_URL_BASE.format(host=hostname)
+ f"/ltm/profile/{profile_type}/{name}"
)
except requests.exceptions.ConnectionError as e:
return _load_connection_error(hostname, e)
if _load_response(response) == "":
return True
else:
return _load_response(response)
Zerion Mini Shell 1.0