F5Networks / f5-appsvcs-extension

F5 BIG-IP Application Services 3 Extension
Apache License 2.0
163 stars 52 forks source link

Any change in /Common partition removes GSLB topology record configuration from other partitions #791

Closed thepowercoders closed 4 months ago

thepowercoders commented 6 months ago

Environment

Summary

We are using topology load balancing on the F5 for routing to different GSLB pools. The GSLB Wide IP and GSLB Pool configuration is held in a separate partition/tenant and configured using an AS3 declaration.

When we run a change in the /Common partition using AS3, it wipes out the configuration for Topology Records, even though this configuration was added in a separate tenant.

Steps To Reproduce

Steps to reproduce the behavior:

  1. Submit the following declaration into the gslb-test partition:

    {
    "class": "AS3",
    "action": "deploy",
    "persist": true,
    "declaration": {
        "class": "ADC",
        "schemaVersion": "3.45.0",
        "gslb-test": {
            "class": "Tenant",
            "topology-test": {
                "class": "Application",
                "wip": {
                    "class": "GSLB_Domain",
                    "domainName": "mywideip.com",
                    "resourceRecordType": "A",
                    "pools": [
                        {
                            "use": "gslb-pool-1"
                        },
                        {
                            "use": "gslb-pool-2"
                        }
                    ],
                    "poolLbMode": "topology"
                },
                "gslb-pool-1": {
                    "class": "GSLB_Pool",
                            "resourceRecordType": "A"
                },
                "gslb-pool-2": {
                    "class": "GSLB_Pool",
                            "resourceRecordType": "A"
                },
                "gslb-topology": {
                    "class": "GSLB_Topology_Records",
                    "records": [
                        {
                            "source": {
                                "matchType": "subnet",
                                "matchOperator": "equals",
                                "matchValue": "192.168.1.0/24"
                            },
                            "destination": {
                                "matchType": "pool",
                                "matchOperator": "equals",
                                "matchValue": {
                                    "use": "gslb-pool-1"
                                }
                            },
                            "weight": 1
                        },
                        {
                            "source": {
                                "matchType": "subnet",
                                "matchOperator": "not-equals",
                                "matchValue": "192.168.1.0/24"
                            },
                            "destination": {
                                "matchType": "pool",
                                "matchOperator": "equals",
                                "matchValue": {
                                    "use": "gslb-pool-2"
                                }
                            },
                            "weight": 1
                        }
                    ]
                }
            }
        }
    }
    }
  2. Observe the following is built:

Wide IP and GSLB Pool using Topology load balancing: image

Topology records: image

  1. Run a declaration in /Common partition - the declaration doesn't need to have any config:
    {
    "class": "AS3",
    "action": "deploy",
    "persist": true,
    "declaration": {
        "class": "ADC",
        "schemaVersion": "3.45.0",
        "Common": {
            "class": "Tenant",
            "Shared": {
                "class": "Application",
                "template": "shared"
            }
        }
    }
    }
  2. Observe that the wide-ip and gslb pool in the gslb-test partition still remains, but that the topology records have been deleted.

Expected Behavior

A change to the configuration being sent using the 'Common' tenant (partition) should not affect configuration which was added into other partitions.

Actual Behavior

We suspect that if the entire GSLB configuration (including all WIPs, Pools and Topology records) was in /Common, this would not occur. However this isn't possible as we have our big-ip configured as multi-tenant. If we move the GSLB_Topology_Record class into /Common, as it is referencing GSLB pools, these would also need to be moved into /Common and so we would lose multi-tenancy separation. We cannot just move the GSLB_Topology_Record configuration as the /Common data needs to be loaded into the device before the partitions, so the reference (even if we used 'bigip' pointer) would fail as it would point to a non-existent pool.

The warnings for AS3 have a message specifically for GSLB here:

"Because BIG-IP AS3 manages topology records globally in /Common, it is required that records are only managed through BIG-IP AS3, as it will treat the records declaratively. If a record is added outside of BIG-IP AS3, it will be removed if it is not included in the next BIG-IP AS3 declaration for topology records (BIG-IP AS3 completely overwrites non-BIG-IP AS3 topologies when a declaration is submitted)."

In this case, we are managing records in AS3 but it looks as if AS3 allows addition of the record in a separate partition, but still writes them into /Common and then deletes them if a subsequent update to /Common is made. I think if this functionality is not available, F5 need to clearly state in clouddocs that GSLB AS3 configuration must be made in /Common and that GSLB configuration should not be put into any other partition. Ideally, AS3 validation should fail if Class GSLB_Topology_Record is used in any tenant other than /Common. Even more strange is that if you perform a DELETE on the gslb-test tenant, it also removes the topology records, even though they appear to be residing in the Common partition.

mdditt2000 commented 6 months ago

Possible duplicate issue of AUTOTOOL-4135 where we are performing  'delete gtm topology all' -- Assigning to myself

mdditt2000 commented 5 months ago

Seems simular issue to AUTOTOOL-4135

thepowercoders commented 5 months ago

@mdditt2000 - also just noticed that any change in ANY another partition wipes the topology data for every other partition. So basically using Class: GSLB_Topology_Records is broken unless you are in /Common. As I said, my pools are all in separate partitions and applications though, so to move GSLB_Topology_Records to /Common, I'd also have to move all GSLB_Pool configuration to /Common which breaks my partitioning security design.

The only way I can get this to work is if I already create all the GSLB pools in the other tenants/partitions and load them into AS3. Then I can reference them in a separate /Common declaration using the "bigip" selector rather than the "use" selector. Problem with this is that there is stuff in /Common which the other tenants/partitions use - so it ends up a chicken and egg problem. I guess I could use a PATCH to add the topology records afterwards, but I want to avoid PATCH if I can.

sunitharonan commented 4 months ago

Thi has been done in AS3 50 release which is planned to release at the end of March, please reach out to us if an early build is required.

thepowercoders commented 3 months ago

@sunitharonan / @mdditt2000 - I've tested Rel. 50 and it does fix the issue reported here but I have noticed that there is still a limitation whereby you can only have a single GSLB_Topology_Records object across all of your partitions/declarations. If you add an additional declaration using a different tenant, the GSLB_Topology_Records config data will still overwrite any existing data in the Topology table. Can I just confirm is this design intent or should another issue be raised for this?

Example: When the following declaration is submitted, the topology table only contains the second entry (from object topology_records_2). Even though it is in a different tenant with a different application and object name, topology_records_1 gets overwritten.

{
    "class": "AS3",
    "action": "deploy",
    "persist": true,
    "declaration": {
        "class": "ADC",
        "schemaVersion": "3.45.0",
        "TEST-TENANT-1": {
            "class": "Tenant",
            "app1": {
                "class": "Application",
                "pool1": {
                    "class": "GSLB_Pool",
                    "enabled": true,
                    "resourceRecordType": "A"
                },
                "topology_records_1": {
                    "class": "GSLB_Topology_Records",
                    "records": [
                        {
                            "source": {
                                "matchType": "subnet",
                                "matchOperator": "equals",
                                "matchValue": "192.168.1.0/24"
                            },
                            "destination": {
                                "matchType": "pool",
                                "matchOperator": "equals",
                                "matchValue": {
                                    "bigip": "/Common/pool1"
                                }
                            },
                            "weight": 1
                        }
                    ]
                }
            }
        },
        "TEST-TENANT-2": {
            "class": "Tenant",
            "app2": {
                "class": "Application",
                "pool2": {
                    "class": "GSLB_Pool",
                    "enabled": true,
                    "resourceRecordType": "A"
                },
                "topology_records_2": {
                    "class": "GSLB_Topology_Records",
                    "records": [
                        {
                            "source": {
                                "matchType": "subnet",
                                "matchOperator": "equals",
                                "matchValue": "192.168.2.0/24"
                            },
                            "destination": {
                                "matchType": "pool",
                                "matchOperator": "equals",
                                "matchValue": {
                                    "use": "pool2"
                                }
                            },
                            "weight": 1
                        }
                    ]
                }
            }
        }
    }
}