Forum Discussion

Greg_Bui_33867's avatar
Greg_Bui_33867
Icon for Nimbostratus rankNimbostratus
Sep 26, 2014

Adding actions to iControlREST transaction

I followed the steps in Chapter 5 of the iControl REST User guide but am unable to get any actions added to a transaction.

The step in "Create a transaction" sub-section that adds a create pool action to the transaction does not work. The text indicates a POST to /mgmt/tm/transaction with create pool JSON but return code is a HTTP 400 using the following curl commands: curl -u xx:xx -k -H "Content-Type: application/json" -X POST https://localhost/mgmt/tm/transaction -d {} curl -u xx:xx -k -H "Content-Type: application/json" -H "X-F5-REST-Coordination-ID: 1411760620" -o C:\Temp\Temp.json -X POST https://localhost:443/mgmt/tm/transaction -d "{\"name\":\"TEST.POOL\",\"partition\":\"webprod\"}"

Response JSON:

{
    "code" : 400,
    "message" : "A transaction id 1411760620 for the user has already created.",
    "errorStack" : []
}

 

I thought this might be a typo in the guide so I changed the second curl command use /mgmt/tm/ltm/pool: curl -u xx:xx -k -H "Content-Type: application/json" -H "X-F5-REST-Coordination-ID: 1411760620" -o C:\Temp\Temp.json -X POST https://localhost:443/mgmt/tm/ltm/pool -d "{\"name\":\"TEST.POOL\",\"partition\":\"webprod\"}"

The response JSON is a HTTP 200, but it returns the newly created pool details instead of the successfully added to transaction response indicated in the user guide. Also, the create pool command is executed immediately instead of when the transaction is committed. If I execute a command to rollback the transaction, the newly created pool is not removed.

Anyone have any luck getting transactions to work successfully through iControlREST? Also, does anyone know how to change the transaction timeout value through iControlREST?

Notes:

* CURL commands were executed using curl 7.34.1-DEV for Windows

* F5 is BIG-IP 11.5.1 Build 4.53.128 Engineering Hotfix HF4

* F5 device name and user/pwd altered for privacy

Regards,

Greg Bui

7 Replies

  • on my side it is working, using 11.6 here is the workflow

     

    1) transaction creation : POST /mgmt/tm/transaction response :

     

    {
       "transId": 1411771265430600,
       "state": "STARTED",
       "timeoutSeconds": 30,
       "kind": "tm:transactionstate",
       "selfLink": "https://localhost/mgmt/tm/transaction/1411771265430600?ver=11.6.0"
    }

    2) adding a command to transaction POST /mgmt/tm/ltm/pool

     

    Header : X-F5-REST-Coordination-Id: 1411771265430600

     

    Payload:

     

     {
    "name":"transac-pool1",
    "members": [ {"name":"192.168.25.32:80","description":"First pool for transactions"} ]
    }

    Response :

     

     {
       "method": "POST",
       "uri": "https://localhost/mgmt/tm/ltm/pool",
       "body":    {
          "name": "transac-pool1",
          "members": [      {
             "name": "192.168.25.32:80",
             "description": "First pool for transactions"
          }]
       },
       "evalOrder": 1,
       "commandId": 1,
       "kind": "tm:transaction:commandsstate",
       "selfLink": "https://localhost/mgmt/tm/transaction/1411771265430600/commands/1?ver=11.6.0"
    }

    i received a 200 OK but if you check the response code is slightly different from a traditional REST call.

     

    3) second call for another pool is doing the same thing

     

    4) having a look to the pending commands : GET /mgmt/tm/transaction/1411771265430600/commands

     

    {
       "kind": "tm:transaction:commandscollectionstate",
       "selfLink": "https://localhost/mgmt/tm/transaction/1411771265430600/commands?ver=11.6.0",
       "items":    [
                {
             "method": "POST",
             "uri": "https://localhost/mgmt/tm/ltm/pool",
             "body":          {
                "name": "transac-pool1",
                "members": [            {
                   "name": "192.168.25.32:80",
                   "description": "First pool for transactions"
                }]
             },
             "evalOrder": 1,
             "commandId": 1,
             "kind": "tm:transaction:commandsstate",
             "selfLink": "https://localhost/mgmt/tm/transaction/1411771265430600/commands/1?ver=11.6.0"
          },
                {
             "method": "POST",
             "uri": "https://localhost/mgmt/tm/ltm/pool",
             "body":          {
                "name": "transac-pool2",
                "members": [            {
                   "name": "192.168.25.32:80",
                   "description": "second pool for transactions"
                }]
             },
             "evalOrder": 2,
             "commandId": 2,
             "kind": "tm:transaction:commandsstate",
             "selfLink": "https://localhost/mgmt/tm/transaction/1411771265430600/commands/2?ver=11.6.0"
          }
       ]
    }

    5) then submit transaction PATCH /mgmt/tm/transaction/1411771265430600

     

    no header !

     

    payload :

     

     { "state":"VALIDATING" }

    response:

     

        {
       "transId": 1411771265430600,
       "state": "COMPLETED",
       "timeoutSeconds": 30,
       "kind": "tm:transactionstate",
       "selfLink": "https://localhost/mgmt/tm/transaction/1411771265430600?ver=11.6.0"
    }

    Having a look to GUI, pool is created.

     

    Regarding you test, the second POST request should be correct, you create a POST as you would do usually but only the header F5-REST-Coordination-Id differentiate it from a normal request.

     

  • Hi Arnaud, I have the same problem but I doing exactly as you explained.

    This is the output of the ssldump of the transcations:

     

    ---------------------------------------------------------------
    POST /mgmt/tm/transaction HTTP/1.1
    Accept: */*; q=0.5, application/xml
    Accept-Encoding: gzip, deflate
    Content-Type: application/json
    Content-Length: 2
    User-Agent: Ruby
    Authorization: Basic YWRtaW46YWRtaW4=
    Host: 192.168.212.172
    ---------------------------------------------------------------
    HTTP/1.1 200 OK
    Date: 28 Dec 2015 12:44:05 UTC
    Server: com.f5.rest.common.RestRequestSender
    Set-Cookie: BIGIPAuthCookie=017EA784717D2DC416AFD90FB58842083DE1BD23; path=/; Secure; HttpOnly
    Set-Cookie: BIGIPAuthUsernameCookie=admin; path=/; Secure; HttpOnly
    X-Frame-Options: SAMEORIGIN
    Cache-Control: no-cache
    Content-Length: 162
    Content-Type: application/json
    X-Content-Type-Options: nosniff
    X-XSS-Protection: 1; mode=block
    Content-Security-Policy: default-src 'self' https://sentinel.whitehatsec.com https://api.ctscloud.com https://key.ctscloud.com 'unsafe-inline' 'unsafe-eval'
    Strict-Transport-Security: max-age=16070400; includeSubDomains
    ---------------------------------------------------------------
    application_data
    ------------------------------------------------------------
    {"transId":1451306645,"state":"STARTED","timeoutSeconds":30,"kind":"tm:transactionstate","selfLink":"https://localhost/mgmt/tm/transaction/1451306645?ver=11.5.1"}
    ---------------------------------------------------------------
    POST /mgmt/tm/ltm/pool HTTP/1.1
    Accept: */*; q=0.5, application/xml
    Accept-Encoding: gzip, deflate
    Content-Type: application/json
    X-F5-Rest-Coordination-Id: 1451306645
    Content-Length: 87
    User-Agent: Ruby
    Authorization: Basic YWRtaW46YWRtaW4=
    Host: 192.168.212.172
    ---------------------------------------------------------------
    application_data
    ---------------------------------------------------------------
    {"name":"www.test1.co.il_HTTP_Pool","partition":"Main","monitor":"Generic_http_lbtest"}
    ---------------------------------------------------------------
    HTTP/1.1 200 OK
    Date: 28 Dec 2015 12:56:16 UTC
    Server: com.f5.rest.common.RestRequestSender
    Set-Cookie: BIGIPAuthCookie=017EA784717D2DC416AFD90FB58842083DE1BD23; path=/; Secure; HttpOnly
    Set-Cookie: BIGIPAuthUsernameCookie=admin; path=/; Secure; HttpOnly
    X-Frame-Options: SAMEORIGIN
    Cache-Control: no-cache
    Content-Length: 868
    Content-Type: application/json
    X-Content-Type-Options: nosniff
    X-XSS-Protection: 1; mode=block
    Content-Security-Policy: default-src 'self' https://sentinel.whitehatsec.com https://api.ctscloud.com https://key.ctscloud.com 'unsafe-inline' 'unsafe-eval'
    Strict-Transport-Security: max-age=16070400; includeSubDomains
    
    ---------------------------------------------------------------
    application_data
    ---------------------------------------------------------------
    {"kind":"tm:ltm:pool:poolstate","name":"www.test1.co.il_HTTP_Pool","partition":"Main","fullPath":"/Main/www.test1.co.il_HTTP_Pool","generation":34258,"selfLink":"https://localhost/mgmt/tm/ltm/pool/~Main~www.test1.co.il_HTTP_Pool?ver=11.5.1","allowNat":"yes","allowSnat":"yes","ignorePersistedWeight":"disabled","ipTosToClient":"pass-through","ipTosToServer":"pass-through","linkQosToClient":"pass-through","linkQosToServer":"pass-through","loadBalancingMode":"round-robin","minActiveMembers":0,"minUpMembers":0,"minUpMembersAction":"failover","minUpMembersChecking":"disabled","monitor":"/Common/Generic_http_lbtest ","queueDepthLimit":0,"queueOnConnectionLimit":"disabled","queueTimeLimit":0,"reselectTries":0,"slowRampTime":10,"membersReference":{"link":"https://localhost/mgmt/tm/ltm/pool/~Main~www.test1.co.il_HTTP_Pool/members?ver=11.5.1","isSubcollection":true}}
    

     

    And then the pool is created without the transaction commit. Any ideas?

    Thanks

  • Hi,

     

    The problem is that the ruby GEM net-http changed the header from:

     

    X-F5-REST-Coordination-Id

     

    to:

     

    X-F5-Rest-Coordination-Id

     

  • My Problem:

     

    I create successfully a transaction and added tasks to it (add a vlan and route-domain). When i check the commands list I get:

     

    object(stdClass)[3]
      public 'kind' => string 'tm:transaction:commandscollectionstate' (length=38)
      public 'selfLink' => string 'https://localhost/mgmt/tm/transaction/1484740224001215/commands?ver=12.1.0' (length=74)
      public 'items' => 
        array (size=2)
          0 => 
            object(stdClass)[4]
              public 'method' => string 'POST' (length=4)
              public 'uri' => string 'https://localhost/mgmt/tm/net/vlan' (length=34)
              public 'body' => 
                object(stdClass)[5]
                  public 'name' => string 'testvlan' (length=8)
                  public 'tag' => string '627' (length=3)
                  public 'interfaces' => 
                    array (size=1)
                      0 => 
                        object(stdClass)[6]
                          ...
              public 'evalOrder' => int 1
              public 'commandId' => int 1
              public 'kind' => string 'tm:transaction:commandsstate' (length=28)
              public 'selfLink' => string 'https://localhost/mgmt/tm/transaction/1484740224001215/commands/1?ver=12.1.0' (length=76)
          1 => 
            object(stdClass)[7]
              public 'method' => string 'POST' (length=4)
              public 'uri' => string 'https://localhost/mgmt/tm/net/route-domain' (length=42)
              public 'body' => 
                object(stdClass)[8]
                  public 'name' => string 'testRD' (length=6)
                  public 'id' => string '4533' (length=4)
                  public 'vlans' => 
                    array (size=1)
                      0 => string '/Common/testvlan' (length=16)
              public 'evalOrder' => int 2
              public 'commandId' => int 2
              public 'kind' => string 'tm:transaction:commandsstate' (length=28)
              public 'selfLink' => string 'https://localhost/mgmt/tm/transaction/1484740224001215/commands/2?ver=12.1.0' (length=76)

    But when I try to commit the transaction, i only get a HTTP 415 and the transaction state stays at "UPDATING".

     

      object(stdClass)[3]
      public 'transId' => string '1484740224001215' (length=16)
      public 'state' => string 'UPDATING' (length=8)
      public 'timeoutSeconds' => int 120
      public 'asyncExecution' => boolean false
      public 'validateOnly' => boolean false
      public 'executionTimeout' => int 300
      public 'executionTime' => int 0
      public 'failureReason' => string '' (length=0)
      public 'kind' => string 'tm:transactionstate' (length=19)
      public 'selfLink' => string 'https://localhost/mgmt/tm/transaction/1484740224001215?ver=12.1.0' (length=65)

    My php/curl transaction function looks like this:

     

    public function executeTransaction($transId)
        {
            $ch = curl_init($this->BASE_URL . "/transaction/" . $transId);
            $encoded_data = '{ "state":"VALIDATING" }';
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
            curl_setopt($ch, CURLOPT_FAILONERROR, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_USERPWD, "$this->username:$this->password");
    
            $result = curl_exec($ch);
            $this->code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            return json_decode($result, false, 512, JSON_BIGINT_AS_STRING);
        }

    Does anyone has a hint for me?

     

  • My Problem:

     

    I create successfully a transaction and added tasks to it (add a vlan and route-domain). When i check the commands list I get:

     

    object(stdClass)[3]
      public 'kind' => string 'tm:transaction:commandscollectionstate' (length=38)
      public 'selfLink' => string 'https://localhost/mgmt/tm/transaction/1484740224001215/commands?ver=12.1.0' (length=74)
      public 'items' => 
        array (size=2)
          0 => 
            object(stdClass)[4]
              public 'method' => string 'POST' (length=4)
              public 'uri' => string 'https://localhost/mgmt/tm/net/vlan' (length=34)
              public 'body' => 
                object(stdClass)[5]
                  public 'name' => string 'testvlan' (length=8)
                  public 'tag' => string '627' (length=3)
                  public 'interfaces' => 
                    array (size=1)
                      0 => 
                        object(stdClass)[6]
                          ...
              public 'evalOrder' => int 1
              public 'commandId' => int 1
              public 'kind' => string 'tm:transaction:commandsstate' (length=28)
              public 'selfLink' => string 'https://localhost/mgmt/tm/transaction/1484740224001215/commands/1?ver=12.1.0' (length=76)
          1 => 
            object(stdClass)[7]
              public 'method' => string 'POST' (length=4)
              public 'uri' => string 'https://localhost/mgmt/tm/net/route-domain' (length=42)
              public 'body' => 
                object(stdClass)[8]
                  public 'name' => string 'testRD' (length=6)
                  public 'id' => string '4533' (length=4)
                  public 'vlans' => 
                    array (size=1)
                      0 => string '/Common/testvlan' (length=16)
              public 'evalOrder' => int 2
              public 'commandId' => int 2
              public 'kind' => string 'tm:transaction:commandsstate' (length=28)
              public 'selfLink' => string 'https://localhost/mgmt/tm/transaction/1484740224001215/commands/2?ver=12.1.0' (length=76)

    But when I try to commit the transaction, i only get a HTTP 415 and the transaction state stays at "UPDATING".

     

      object(stdClass)[3]
      public 'transId' => string '1484740224001215' (length=16)
      public 'state' => string 'UPDATING' (length=8)
      public 'timeoutSeconds' => int 120
      public 'asyncExecution' => boolean false
      public 'validateOnly' => boolean false
      public 'executionTimeout' => int 300
      public 'executionTime' => int 0
      public 'failureReason' => string '' (length=0)
      public 'kind' => string 'tm:transactionstate' (length=19)
      public 'selfLink' => string 'https://localhost/mgmt/tm/transaction/1484740224001215?ver=12.1.0' (length=65)

    My php/curl transaction function looks like this:

     

    public function executeTransaction($transId)
        {
            $ch = curl_init($this->BASE_URL . "/transaction/" . $transId);
            $encoded_data = '{ "state":"VALIDATING" }';
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
            curl_setopt($ch, CURLOPT_FAILONERROR, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_USERPWD, "$this->username:$this->password");
    
            $result = curl_exec($ch);
            $this->code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            return json_decode($result, false, 512, JSON_BIGINT_AS_STRING);
        }

    Does anyone has a hint for me?

     

    • Ichnafi_177360's avatar
      Ichnafi_177360
      Icon for Nimbostratus rankNimbostratus

      To Answer my own Question:

      You have to specify a header with Content-Type (and optional Content-Length) BUT you have to omit the 'X-F5-REST-Coordination-Id:' in it. So I added the follwing curl-option to my function. It works now.

       

      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                  'Content-Type: application/json',
                  'Content-Length: ' . strlen($encoded_data))
              );
      

       

    • Ichnafi's avatar
      Ichnafi
      Icon for Cirrostratus rankCirrostratus

      To Answer my own Question:

      You have to specify a header with Content-Type (and optional Content-Length) BUT you have to omit the 'X-F5-REST-Coordination-Id:' in it. So I added the follwing curl-option to my function. It works now.

       

      curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                  'Content-Type: application/json',
                  'Content-Length: ' . strlen($encoded_data))
              );