Skip to content

Commit 0f839ab

Browse files
authored
handle error in operations' result from transact method correctly (eBay#96)
the results of the operations specified in the transact method is not correctly verified. we need to always walk through the operations' results to check for null error to claim a transaction has succeded. furthermore, per RFC 7047 section 4.1.3, if all of the operations succeed, but the results cannot be committed, then "result" will have one more element than "params", with the additional element being an <error>. this case was not handled as well. with the fix in place, errors related to "constraint violation", "referential integrity violation", "resources exhausted", and "I/O error" are being caught. Signed-off-by: Girish Moodalbail <[email protected]>
1 parent d2abdc5 commit 0f839ab

File tree

3 files changed

+70
-7
lines changed

3 files changed

+70
-7
lines changed

chassis_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ import (
2121
)
2222

2323
const (
24-
CHASSIS_HOSTNAME = "fakehost"
25-
CHASSIS_NAME = "fakechassis"
26-
IP = "10.0.0.11"
24+
CHASSIS_HOSTNAME = "fakehost"
25+
CHASSIS_NAME = "fakechassis"
26+
IP = "10.0.0.11"
27+
CHASSIS2_HOSTNAME = "fakehost2"
28+
CHASSIS2_NAME = "fakechassis2"
2729
)
2830

2931
// can be one or many encap_types similar to chassis-add of sbctl

ovnimp.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ import (
2525
"github.com/ebay/libovsdb"
2626
)
2727

28+
const (
29+
commitTransactionText = "commiting transaction"
30+
)
31+
2832
var (
2933
// ErrorOption used when invalid args specified
3034
ErrorOption = errors.New("invalid option specified")
@@ -149,12 +153,23 @@ func (odbi *ovndb) transact(db string, ops ...libovsdb.Operation) ([]libovsdb.Op
149153
return reply, err
150154
}
151155

152-
if len(reply) < len(ops) {
153-
for i, o := range reply {
154-
if o.Error != "" && i < len(ops) {
155-
return nil, fmt.Errorf("Transaction Failed due to an error : %v details: %v in %v", o.Error, o.Details, ops[i])
156+
// Per RFC 7047 Section 4.1.3, the operation result array in the transact response object
157+
// maps one-to-one with operations array in the transact request object. We need to check
158+
// each of the operation result for null error to ensure that the transaction has succeeded.
159+
for i, o := range reply {
160+
if o.Error != "" {
161+
// Per RFC 7047 Section 4.1.3, if all of the operations succeed, but the results
162+
// cannot be committed, then "result" will have one more element than "params",
163+
// with the additional element being an <error>.
164+
opsInfo := commitTransactionText
165+
if i < len(ops) {
166+
opsInfo = fmt.Sprintf("%v", ops[i])
156167
}
168+
return nil, fmt.Errorf("Transaction Failed due to an error: %v details: %v in %s",
169+
o.Error, o.Details, opsInfo)
157170
}
171+
}
172+
if len(reply) < len(ops) {
158173
return reply, fmt.Errorf("Number of Replies should be atleast equal to number of operations")
159174
}
160175
return reply, nil

ovnimp_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package goovn
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestBadTransact(t *testing.T) {
10+
ovndbapi := getOVNClient(DBSB)
11+
t.Logf("Adding Chassis to OVN SB DB")
12+
ocmd, err := ovndbapi.ChassisAdd(CHASSIS_NAME, CHASSIS_HOSTNAME, ENCAP_TYPES, IP, nil, nil, nil)
13+
if err != nil {
14+
t.Fatal(err)
15+
}
16+
err = ovndbapi.Execute(ocmd)
17+
if err != nil {
18+
t.Fatalf("Adding Chassis to OVN failed with err %v", err)
19+
}
20+
t.Logf("Adding Chassis to OVN Done")
21+
22+
t.Logf("Adding second Chassis to OVN SB DB but with same ENCAP_TYPES and IP")
23+
ocmd, err = ovndbapi.ChassisAdd(CHASSIS2_NAME, CHASSIS2_HOSTNAME, ENCAP_TYPES, IP, nil, nil, nil)
24+
if err != nil {
25+
t.Fatal(err)
26+
}
27+
28+
// expecting constraint violation error with following details -- "Transaction causes multiple
29+
// rows in \"Encap\" table to have identical values (stt and \"10.0.0.11\") for index on columns
30+
// \"type\" and \"ip\". First row, with UUID 9860cf40-bd82-4c24-9514-05b225434934, existed in
31+
// the database before this transaction and was not modified by the transaction. Second row,
32+
// with UUID 10d7d018-7444-48de-89fc-cb062f88e520, was inserted by this transaction."
33+
err = ovndbapi.Execute(ocmd)
34+
assert.Error(t, err)
35+
36+
t.Logf("Deleting Chassis:%v", CHASSIS_NAME)
37+
ocmd, err = ovndbapi.ChassisDel(CHASSIS_NAME)
38+
if err != nil && err != ErrorNotFound {
39+
t.Fatal(err)
40+
}
41+
42+
err = ovndbapi.Execute(ocmd)
43+
if err != nil {
44+
t.Fatalf("err executing command:%v", err)
45+
}
46+
}

0 commit comments

Comments
 (0)