Skip to content
Open
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
50 changes: 35 additions & 15 deletions f5_ctlr_agent/bigipconfigdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import logging
import os
import os.path
import re
import signal
import socket
import sys
Expand Down Expand Up @@ -633,8 +634,8 @@ def _do_reset(self):
log.info('SCALE_PERF: Test data: %s',
json_data)

log.debug('updating tasks finished, took %s seconds',
time.time() - start_time)
log.info('updating tasks finished, took %s seconds',
time.time() - start_time)

if self._interval:
self._interval.stop()
Expand Down Expand Up @@ -705,26 +706,30 @@ def _update_gtm(self, config):

GTMUtils.pre_process_gtm(newGtmConfig, disabled_availability_zones=disabled_zones)
isConfigSame = sorted(oldGtmConfig.items()) == sorted(newGtmConfig.items())
_bip = mgr._gtm._bigip_host
_wip_count = len(newGtmConfig.get(partition, {}).get('wideIPs', []) or [])
if not isConfigSame and len(oldGtmConfig) == 0:
if partition in newGtmConfig:
mgr._gtm.create_gtm(
partition,
newGtmConfig)
mgr._gtm.replace_gtm_config(allConfig)
log.info("GTM: Initial push/sync on restart completed successfully ({} wideIPs)".format(
len(newGtmConfig.get(partition, {}).get('wideIPs', []) or [])))
log.info("GTM: Initial push/sync on restart completed successfully ({} wideIPs), bigip: {}".format(
_wip_count, _bip))
elif not isConfigSame:
log.info("New changes observed in gtm config")
log.info("New changes observed in gtm config, bigip: %s", _bip)
if partition in newGtmConfig:
mgr._gtm.delete_update_gtm(
partition,
newGtmConfig)
mgr._gtm.replace_gtm_config(allConfig)
log.info("GTM: Config sync completed successfully ({} wideIPs)".format(
len(newGtmConfig.get(partition, {}).get('wideIPs', []) or [])))
log.info("GTM: Config sync completed successfully ({} wideIPs), bigip: {}".format(
_wip_count, _bip))

except F5CcclError as e:
log.error("GTM Error.....:%s", e.msg)
_bip = mgr._gtm._bigip_host if hasattr(mgr, '_gtm') and mgr._gtm else 'unknown'
_code = _extract_http_code(str(e))
log.error("GTM Error.....:%s, bigip: %s, error_code: %s", e.msg, _bip, _code)
gtmIncomplete += 1
return gtmIncomplete

Expand Down Expand Up @@ -970,6 +975,10 @@ def __init__(self, bigip, partition, user_agent=None, local_cluster_name=None,
self._local_cluster_name = local_cluster_name or ""
self._cluster_digital_asset_id = cluster_digital_asset_id or ""
self._namespace = namespace or "" # Top-level namespace for pools without explicit namespace
try:
self._bigip_host = bigip._meta_data.get('hostname', 'unknown')
except Exception:
self._bigip_host = 'unknown'
if not self._local_cluster_name and not self._cluster_digital_asset_id:
log.info("GTM: Running in legacy unscoped mode — all GTM objects will be "
"treated as owned by this CIS instance as cluster identifier and digital asset ID are not set. ")
Expand Down Expand Up @@ -1182,8 +1191,9 @@ def handle_operation_delete(self, gtm, partition, opr_config, rev_map, incoming_
self._remove_wideip_from_config(working_config, partition, wideip_name)

except F5CcclError as e:
log.error("GTM: Error while handling delete operation (Steps 1-3): %s", e)
# Do NOT commit working_config; self._gtm_config remains unchanged for retry
code = _extract_http_code(str(e))
log.error("GTM: Error while handling delete operation (Steps 1-3): %s, bigip: %s, error_code: %s",
e, self._bigip_host, code)
raise e

# CRITICAL FIX: Commit BEFORE cleanup phase
Expand Down Expand Up @@ -1442,8 +1452,9 @@ def handle_operation_create(self, gtm, partition, gtmConfig, opr_config, opr):
raise e

except F5CcclError as e:
log.error("GTM: Error while handling create operation: %s", e)
# Do NOT commit working_config; self._gtm_config remains unchanged for retry
code = _extract_http_code(str(e))
log.error("GTM: Error while handling create operation: %s, bigip: %s, error_code: %s",
e, self._bigip_host, code)
raise e

# Commit BEFORE cleanup phase — ensures successful creates are recorded
Expand Down Expand Up @@ -1668,7 +1679,9 @@ def create_gtm(self, partition, gtmConfig):
partition, processed + skipped, processed, skipped))

except F5CcclError as e:
log.error("GTM: Error while creating gtm: %s", e)
code = _extract_http_code(str(e))
log.error("GTM: Error while creating gtm: %s, bigip: %s, error_code: %s",
e, self._bigip_host, code)
raise e

# PERF FIX #9: Cache BIG-IP version
Expand Down Expand Up @@ -2040,6 +2053,12 @@ def _set_user_agent(prefix):
return user_agent


def _extract_http_code(error_msg):
"""Extract HTTP status code from an error string, defaulting to 500."""
m = re.search(r'\b([45]\d{2})\b', str(error_msg))
return m.group(1) if m else '500'


def _is_non_retryable_error(error_message):
"""Return True when an error indicates permanent auth failure."""
if not error_message:
Expand Down Expand Up @@ -2236,10 +2255,11 @@ def _gtmbigip_connect_cb(log_success):
"tmos",
ca_certs=gtm_ca_certs_path)
if log_success:
log.info('GTM BIG-IP connection established.')
log.info('GTM BIG-IP connection established, bigip: %s', host)
return (True, bigip)
except Exception as e:
error = 'GTM BIG-IP connection error: {}'.format(e)
code = _extract_http_code(str(e))
error = 'GTM BIG-IP connection error: {}, bigip: {}, error_code: {}'.format(e, host, code)
return (False, error, _is_non_retryable_error(error))

managers = []
Expand Down