-
Notifications
You must be signed in to change notification settings - Fork 8
/
transaction.go
141 lines (117 loc) · 4.68 KB
/
transaction.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
Copyright 2023 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package knftables
import (
"bytes"
"fmt"
)
// Transaction represents an nftables transaction
type Transaction struct {
*nftContext
operations []operation
err error
}
// operation contains a single nftables operation (eg "add table", "flush chain")
type operation struct {
verb verb
obj Object
}
// verb is used internally to represent the different "nft" verbs
type verb string
const (
addVerb verb = "add"
createVerb verb = "create"
insertVerb verb = "insert"
replaceVerb verb = "replace"
deleteVerb verb = "delete"
flushVerb verb = "flush"
)
// populateCommandBuf populates the transaction as series of nft commands to the given bytes.Buffer.
func (tx *Transaction) populateCommandBuf(buf *bytes.Buffer) error {
if tx.err != nil {
return tx.err
}
for _, op := range tx.operations {
op.obj.writeOperation(op.verb, tx.nftContext, buf)
}
return nil
}
// String returns the transaction as a string containing the nft commands; if there is
// a pending error, it will be output as a comment at the end of the transaction.
func (tx *Transaction) String() string {
buf := &bytes.Buffer{}
for _, op := range tx.operations {
op.obj.writeOperation(op.verb, tx.nftContext, buf)
}
if tx.err != nil {
fmt.Fprintf(buf, "# ERROR: %v", tx.err)
}
return buf.String()
}
// NumOperations returns the number of operations queued in the transaction.
func (tx *Transaction) NumOperations() int {
return len(tx.operations)
}
func (tx *Transaction) operation(verb verb, obj Object) {
if tx.err != nil {
return
}
if tx.err = obj.validate(verb); tx.err != nil {
return
}
tx.operations = append(tx.operations, operation{verb: verb, obj: obj})
}
// Add adds an "nft add" operation to tx, ensuring that obj exists by creating it if it
// did not already exist. (If obj is a Rule, it will be appended to the end of its chain,
// or else added after the Rule indicated by this rule's Index or Handle.) The Add() call
// always succeeds, but if obj is invalid, or inconsistent with the existing nftables
// state, then an error will be returned when the transaction is Run.
func (tx *Transaction) Add(obj Object) {
tx.operation(addVerb, obj)
}
// Create adds an "nft create" operation to tx, creating obj, which must not already
// exist. (If obj is a Rule, it will be appended to the end of its chain, or else added
// after the Rule indicated by this rule's Index or Handle.) The Create() call always
// succeeds, but if obj is invalid, already exists, or is inconsistent with the existing
// nftables state, then an error will be returned when the transaction is Run.
func (tx *Transaction) Create(obj Object) {
tx.operation(createVerb, obj)
}
// Insert adds an "nft insert" operation to tx, inserting obj (which must be a Rule) at
// the start of its chain, or before the other Rule indicated by this rule's Index or
// Handle. The Insert() call always succeeds, but if obj is invalid or is inconsistent
// with the existing nftables state, then an error will be returned when the transaction
// is Run.
func (tx *Transaction) Insert(obj Object) {
tx.operation(insertVerb, obj)
}
// Replace adds an "nft replace" operation to tx, replacing an existing rule with obj
// (which must be a Rule). The Replace() call always succeeds, but if obj is invalid, does
// not contain the Handle of an existing rule, or is inconsistent with the existing
// nftables state, then an error will be returned when the transaction is Run.
func (tx *Transaction) Replace(obj Object) {
tx.operation(replaceVerb, obj)
}
// Flush adds an "nft flush" operation to tx, clearing the contents of obj. The Flush()
// call always succeeds, but if obj does not exist (or does not support flushing) then an
// error will be returned when the transaction is Run.
func (tx *Transaction) Flush(obj Object) {
tx.operation(flushVerb, obj)
}
// Delete adds an "nft delete" operation to tx, deleting obj. The Delete() call always
// succeeds, but if obj does not exist or cannot be deleted based on the information
// provided (eg, Handle is required but not set) then an error will be returned when the
// transaction is Run.
func (tx *Transaction) Delete(obj Object) {
tx.operation(deleteVerb, obj)
}