F5Networks / f5-common-python

Python SDK for configuration and monitoring of F5® BIG-IP® devices via the iControl® REST API.
https://f5-sdk.readthedocs.org
Apache License 2.0
262 stars 134 forks source link

problem with transactions using f5-sdk 1.3.1 and 11.6.1 #641

Closed chen23 closed 8 years ago

chen23 commented 8 years ago

Testing on 11.6.1 w/ f5-sdk 1.3.1 ran into two issues with transactions

  1. transaction ID is seen as an "int" and causes the request to fail
  2. retrieving a "created" object messes up 'uri' and subsequent requests

I've patched my code to workaround the issues, not sure the best way to handle for the F5 Python SDK

Errors seen:

  1. error creating dora.local.pcfdev.io Header value 1471619352790463 must be of type str or bytes, not <type 'int'>
Traceback (most recent call last):
  File "cf2bigip-bad.py", line 592, in <module>
    sp.create_app(app_name, row[2], args.policy_name)
  File "cf2bigip-bad.py", line 339, in create_app
    pool_member = pool.members_s.members.create(partition=partition, name=member, priorityGroup=priority_group)
  File "/home/erchen/projects/pcf2bigip/venv/lib/python2.7/site-packages/f5/bigip/resource.py", line 851, in create
    return self._create(**kwargs)
  File "/home/erchen/projects/pcf2bigip/venv/lib/python2.7/site-packages/f5/bigip/resource.py", line 818, in _create
    response = session.post(_create_uri, json=kwargs, **requests_params)
  File "/home/erchen/projects/pcf2bigip/venv/lib/python2.7/site-packages/icontrol/session.py", line 230, in wrapper
    raise iControlUnexpectedHTTPError(error_message, response=response)
icontrol.exceptions.iControlUnexpectedHTTPError: 400 Unexpected Error: Bad Request for uri: https://10.1.10.240:443/mgmt/tm/transaction/1471619427763099/commands/2/members/
Text: u'{"code":400,"message":"Found invalid command id 2/members/","errorStack":[]}'

Code that avoids errors:

        with TransactionContextManager(self.tx) as api:
            # deal with ERROR #1: int vs. str
            api._meta_data['icr_session'].session.headers['X-F5-REST-Coordination-Id'] = api._meta_data['icr_session'].session.headers['X-F5-REST-Coordination-Id'].__str__()
            monitor = api.tm.ltm.monitor.https.http.create(name=monitor_name, partition=partition, interval=10, timeout=31, send=send_str, recv=recv_str)
            pool_path = "/%s/%s" % (partition, pool_name)

            pool = api.tm.ltm.pools.pool.create(partition=partition, name=pool_name, minActiveMembers=1, monitor=monitor_name)
            print "Created pool %s" % pool_path

            member_list = pool_members.split(',')
            member_list.reverse()
            priority_group = 0
            for member in member_list:
                # deal with ERROR #2 incorrect URI path
                pool._meta_data['uri'] = pool._meta_data['uri'].split("/transaction/")[0] + "/ltm/pool/~%s~%s/" %(partition,pool_name)
                pool_member = pool.members_s.members.create(partition=partition, name=member, priorityGroup=priority_group)
                priority_group += 10
                print " Added member %s" % member

            policy = api.tm.ltm.policys.policy.load(name = policy_name, partition = partition)

            rules = policy.rules_s.get_collection()

            my_rule = policy.rules_s.rules.create(name=app_name)

            payload = {u'caseInsensitive': True,
                   u'equals': True,
                   u'external': True,
                   u'fullPath': u'0',
                   u'host': True,
                   u'httpHost': True,
                   u'index': 0,
                   u'name': u'0',
                   u'present': True,
                   u'remote': True,
                   u'request': True,
                   u'values': [app_name]}
            # deal with ERROR #2 incorrect URI path
            my_rule._meta_data['uri'] = policy._meta_data['uri'] + 'rules/' + app_name + '/'
            my_rule.conditions_s.conditions.create(**payload)
            payload = {
                "vlanId": 0,
                "forward": True,
                "code": 0,
                "fullPath": "0",
                "name": "0",
                "pool": pool_name,
                "request": True,
                "select": True,
                "status": 0
        }
            my_rule.actions_s.actions.create(**payload)
zancas commented 8 years ago

@chen23 how about deleting the pool_path = line and having the print debug statement that used it be:

print("Created pool %s" % pool.selfLink)

instead?

zancas commented 8 years ago

Instead of directly calling instance.__str__() call str(instance).

chen23 commented 8 years ago

Here's the output with the suggested changes:

 python cf2bigip-bad.py -f create.csv 10.1.1.5
create.csv
Created pool https://localhost/mgmt/tm/transaction/1471889627257896/commands/2?ver=11.6.1
 Added member 192.168.11.11:80
Created policy rule dora.local.pcfdev.io
caphrim007 commented 8 years ago

@chen23 do you have code I can use to reproduce?

zancas commented 8 years ago

And I!

caphrim007 commented 8 years ago

This is a breaking change introduced in requests 2.11 https://github.com/kennethreitz/requests/issues/3477

chen23 commented 8 years ago

A bit late. Here's the code: https://github.com/f5devcentral/f5-icontrol-codeshare-python/tree/master/pcf-example, use pcf-phase1.py.

The issue had two issues: 1. transaction ID in header 2. URI getting mangled during a transaction. Let me know if I should open a new ticket for the second issue, reopen, or leave my code as-is. Thanks.

r4mbo7 commented 4 years ago

Thanks @chen23 for your fixes !

I tried to create a virtual server with a member using a same transaction. Using f5-sdk==3.0.21

E           icontrol.exceptions.iControlUnexpectedHTTPError: 400 Unexpected Error: Bad Request for uri: https://lb-bigip01/mgmt/tm/transaction/1583156579056330/commands/3/members/
E           Text: '{"code":400,"message":"Found invalid command id 3/members/","errorStack":[],"apiError":1}'

Code to reproduce

host = os.getenv("BIGIP_BENCH_HOST")
user = os.getenv("BIGIP_BENCH_USER")
password = os.getenv("BIGIP_BENCH_PASSWORD")
mgmt = ManagementRoot(host, user, password)
tx = mgmt.tm.transactions.transaction
with TransactionContextManager(tx) as api:
    https_monitor = api.tm.ltm.monitor.https_s.https.create(name="MyHttpsMonitor")
    # create a node
    node = api.tm.ltm.nodes.node.create(name="MyNode", address="1.2.3.4")
    # create a pool
    pool_name = "MyPool"
    partition = "Common"
    pool = api.tm.ltm.pools.pool.create(
        name=pool_name,
        loadBalancingMode="round-robin",
        monitor="MyHttpsMonitor",
        partition=partition
    )
    # Fixes {"code":400,"message":"Found invalid command id 3/members/","errorStack":[],"apiError":1}
    # pool._meta_data['uri'] = pool._meta_data['uri'].split("/transaction/")[0] + "/ltm/pool/~%s~%s/" %(partition, pool_name)
    # create a pool member - inherit monitor from pool.
    member = pool.members_s.members.create(
        name="MyNode:42", address="1.2.3.4", partition="Common"
    )
    # create vip
    vip = api.tm.ltm.virtuals.virtual.create(
        name="MyVip", pool=pool_name, source="0.0.0.0/0", destination="1.2.3.4:42"
    )