Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix dos profile #2425

Merged
merged 6 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ examples/hosts.ini
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
.venv/*

# Sensitive or high-churn files
.idea/**/dataSources/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
minor_changes:
- bigip_device_info - virtual-servers - return per_flow_request_access_policy if defined.
- bigip_virtual_server - set per_flow_request_access_policy and stay idempotent.
- bigip_asm_dos_application - add support for creating dos profile.
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def send(self, method, url, **kwargs):

if not data and json is not None:
self.request.headers.update(BASE_HEADERS)
body = _json.dumps(json)
body = _json.dumps(json, ensure_ascii=False)
if not isinstance(body, bytes):
body = body.encode('utf-8')
if data:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,21 @@ def profile_exists(self):
raise F5ModuleError(str(ex))

if resp.status == 404 or 'code' in response and response['code'] == 404:
return False
uri = "https://{0}:{1}/mgmt/tm/security/dos/profile".format(
self.client.provider['server'],
self.client.provider['server_port'],
)
payload = {'name': self.want.profile, 'partition': self.want.partition}
resp = self.client.api.post(uri, json=payload)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
# response = resp.json()
if resp.status == 404 or 'code' in response and response['code'] == 404:
return False
if resp.status in [200, 201] or 'code' in response and response['code'] in [200, 201]:
return True
if resp.status in [200, 201] or 'code' in response and response['code'] in [200, 201]:
return True

Expand All @@ -1148,16 +1162,11 @@ def profile_exists(self):

def exists(self):
errors = [401, 403, 409, 500, 501, 502, 503, 504]
if not self.profile_exists():
raise F5ModuleError(
'Specified DOS profile: {0} on partition: {1} does not exist.'.format(
self.want.profile, self.want.partition)
)
uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/application/{3}".format(

uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}".format(
self.client.provider['server'],
self.client.provider['server_port'],
transform_name(self.want.partition, self.want.profile),
self.want.profile
)
resp = self.client.api.get(uri)
try:
Expand All @@ -1169,7 +1178,6 @@ def exists(self):
return False
if resp.status in [200, 201] or 'code' in response and response['code'] in [200, 201]:
return True

if resp.status in errors or 'code' in response and response['code'] in errors:
if 'message' in response:
raise F5ModuleError(response['message'])
Expand All @@ -1179,6 +1187,19 @@ def exists(self):
def create_on_device(self):
params = self.changes.api_params()
params['name'] = self.want.profile
uri = "https://{0}:{1}/mgmt/tm/security/dos/profile".format(
self.client.provider['server'],
self.client.provider['server_port'],
)
payload = {'name': self.want.profile, 'partition': self.want.partition}

resp = self.client.api.post(uri, json=payload)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if resp.status == 404 or 'code' in response and response['code'] == 404:
raise F5ModuleError(resp.content)
uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/application/".format(
self.client.provider['server'],
self.client.provider['server_port'],
Expand Down Expand Up @@ -1213,11 +1234,10 @@ def update_on_device(self):
raise F5ModuleError(resp.content)

def remove_from_device(self):
uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/application/{3}".format(
uri = "https://{0}:{1}/mgmt/tm/security/dos/profile/{2}/".format(
self.client.provider['server'],
self.client.provider['server_port'],
transform_name(self.want.partition, self.want.profile),
self.want.profile
)
response = self.client.api.delete(uri)
if response.status == 200:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7454,6 +7454,12 @@
returned: queried
type: str
sample: tcp
per_flow_request_access_policy:
description:
- per request policy.
returned: queried
type: str
sample: /Common/my-custom-per-request-policy
total_requests:
description:
- Total requests.
Expand Down Expand Up @@ -17114,6 +17120,7 @@ class VirtualServersParameters(BaseParameters):
'securityLogProfiles': 'security_log_profiles',
'profilesReference': 'profiles',
'policiesReference': 'policies',
'perFlowRequestAccessPolicy': 'per_flow_request_access_policy',
}

returnables = [
Expand Down Expand Up @@ -17153,6 +17160,7 @@ class VirtualServersParameters(BaseParameters):
'type',
'policies',
'profiles',
'per_flow_request_access_policy',
'destination_address',
'destination_port',
'availability_status',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@
elements: str
aliases:
- all_policies
per_flow_request_access_policy:
description:
- Specifies the Per-Request access policy for the virtual server.
type: str
snat:
description:
- Source network address policy.
Expand Down Expand Up @@ -811,6 +815,11 @@
returned: changed
type: list
sample: ['/Common/policy1', '/Common/policy2']
per_flow_request_access_policy:
description: Per-request policy attached to the virtual.
returned: changed
type: str
sample: '/Common/sample_per-request_policy'
port:
description: Port the virtual server is configured to listen on.
returned: changed
Expand Down Expand Up @@ -981,7 +990,8 @@ class Parameters(AnsibleF5Parameters):
'rateLimitSrcMask': 'rate_limit_src_mask',
'clonePools': 'clone_pools',
'autoLasthop': 'auto_last_hop',
'serviceDownImmediateAction': 'service_down_immediate_action'
'serviceDownImmediateAction': 'service_down_immediate_action',
'perFlowRequestAccessPolicy': 'per_flow_request_access_policy',
}

api_attributes = [
Expand Down Expand Up @@ -1025,6 +1035,7 @@ class Parameters(AnsibleF5Parameters):
'rateLimitSrcMask',
'clonePools',
'autoLasthop',
'perFlowRequestAccessPolicy',
]

updatables = [
Expand Down Expand Up @@ -1062,6 +1073,7 @@ class Parameters(AnsibleF5Parameters):
'rate_limit_dst_mask',
'clone_pools',
'auto_last_hop',
'per_flow_request_access_policy',
]

returnables = [
Expand Down Expand Up @@ -1103,6 +1115,7 @@ class Parameters(AnsibleF5Parameters):
'rate_limit_dst_mask',
'clone_pools',
'auto_last_hop',
'per_flow_request_access_policy',
]

profiles_mutex = [
Expand Down Expand Up @@ -1627,13 +1640,16 @@ def profiles(self):
return None
result = []
prof_path = 'https://localhost/mgmt/tm/ltm/profile/'
accprof_path = 'https://localhost/mgmt/tm/apm/profile/access'
for item in self._values['profiles']['items']:
context = item['context']
name = item['name']
path = item['nameReference']['link']
if context in ['all', 'serverside', 'clientside']:
if path.startswith(prof_path):
result.append(dict(name=name, context=context, fullPath=item['fullPath']))
if path.startswith(accprof_path):
result.append(dict(name=name, context=context, fullPath=item['fullPath']))
else:
raise F5ModuleError(
"Unknown profile context found: '{0}'".format(context)
Expand Down Expand Up @@ -2631,6 +2647,7 @@ def check_update(self):

def check_create(self):
# Regular checks
self._verify_virtual_has_required_parameters()
self._set_default_ip_protocol()
self._set_default_profiles()
self._override_port_by_type()
Expand All @@ -2639,7 +2656,6 @@ def check_create(self):
self._verify_default_persistence_profile_for_type()
self._verify_fallback_persistence_profile_for_type()
self._update_persistence_profile()
self._verify_virtual_has_required_parameters()
self._ensure_server_type_supports_vlans()
self._override_vlans_if_all_specified()
self._check_source_and_destination_match()
Expand Down Expand Up @@ -3629,6 +3645,9 @@ def create_on_device(self):
params = self.changes.api_params()
params['name'] = self.want.name
params['partition'] = self.want.partition
if 'destination' not in params:
params['destination'] = f"/Common/0.0.0.0:{self.want.port}"
params['mask'] = "255.255.255.255"
if self.want.insert_metadata:
# Mark the resource as managed by Ansible, this is default behavior
params = mark_managed_by(self.module.ansible_version, params)
Expand Down Expand Up @@ -3743,6 +3762,7 @@ def __init__(self):
service_down_immediate_action=dict(
choices=['drop', 'none', 'reset']
),
per_flow_request_access_policy=dict(),
security_log_profiles=dict(
type='list',
elements='str',
Expand Down
29 changes: 18 additions & 11 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
ansible>=8.5.0
q
invoke~=1.7.3
Jinja2~=3.1.2
invoke==2.2.0
pycodestyle==2.12.1
flake8==7.1.1
nose
mock
semver
pytest
pytest-cov
coverage
packaging
semver~=2.13.0
pytest~=7.2.0
PyYAML~=6.0
netaddr~=0.8.0
packaging~=21.3
ordereddict~=1.1
cryptography~=42.0.8
objectpath~=0.6.1
antsibull-changelog
ansible-lint
paramiko
jinja2
netaddr
objectpath
PyYAML
ordereddict
cryptography