Skip to content

Commit c57e825

Browse files
authored
Merge pull request #17 from cybozu-go/refactor
Refactor implementation
2 parents 98c7b0f + 9f034e1 commit c57e825

File tree

8 files changed

+116
-192
lines changed

8 files changed

+116
-192
lines changed

cmd/npv/app/const.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package app
2+
3+
import "k8s.io/apimachinery/pkg/runtime/schema"
4+
5+
const (
6+
directionEgress = "Egress"
7+
directionIngress = "Ingress"
8+
9+
policyAllow = "Allow"
10+
policyDeny = "Deny"
11+
)
12+
13+
var gvrEndpoint schema.GroupVersionResource = schema.GroupVersionResource{
14+
Group: "cilium.io",
15+
Version: "v2",
16+
Resource: "ciliumendpoints",
17+
}
18+
19+
var gvrIdentity schema.GroupVersionResource = schema.GroupVersionResource{
20+
Group: "cilium.io",
21+
Version: "v2",
22+
Resource: "ciliumidentities",
23+
}
24+
25+
var gvrNetworkPolicy schema.GroupVersionResource = schema.GroupVersionResource{
26+
Group: "cilium.io",
27+
Version: "v2",
28+
Resource: "ciliumnetworkpolicies",
29+
}
30+
31+
var gvrClusterwideNetworkPolicy schema.GroupVersionResource = schema.GroupVersionResource{
32+
Group: "cilium.io",
33+
Version: "v2",
34+
Resource: "ciliumclusterwidenetworkpolicies",
35+
}

cmd/npv/app/helper.go

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,25 @@ package app
22

33
import (
44
"context"
5+
"encoding/json"
56
"errors"
67
"fmt"
7-
"math/rand"
8+
"io"
89
"strconv"
910
"strings"
11+
"text/tabwriter"
1012

1113
"github.com/cilium/cilium/pkg/client"
1214
corev1 "k8s.io/api/core/v1"
1315
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1416
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
15-
"k8s.io/apimachinery/pkg/runtime/schema"
1617
"k8s.io/client-go/dynamic"
1718
"k8s.io/client-go/kubernetes"
1819
"k8s.io/client-go/rest"
1920
)
2021

21-
const (
22-
directionEgress = "Egress"
23-
directionIngress = "Ingress"
24-
25-
policyAllow = "Allow"
26-
policyDeny = "Deny"
27-
)
28-
2922
var cachedCiliumClients map[string]*client.Client
3023

31-
var gvrEndpoint schema.GroupVersionResource = schema.GroupVersionResource{
32-
Group: "cilium.io",
33-
Version: "v2",
34-
Resource: "ciliumendpoints",
35-
}
36-
37-
var gvrIdentity schema.GroupVersionResource = schema.GroupVersionResource{
38-
Group: "cilium.io",
39-
Version: "v2",
40-
Resource: "ciliumidentities",
41-
}
42-
4324
func init() {
4425
cachedCiliumClients = make(map[string]*client.Client)
4526
}
@@ -142,34 +123,56 @@ func getIdentityResourceMap(ctx context.Context, d *dynamic.DynamicClient) (map[
142123
}
143124

144125
// key: identity number
145-
// value: example pod name
146-
func getIdentityExampleMap(ctx context.Context, d *dynamic.DynamicClient) (map[int]string, error) {
126+
// value: CiliumEndpoint array
127+
func getIdentityEndpoints(ctx context.Context, d *dynamic.DynamicClient) (map[int][]*unstructured.Unstructured, error) {
147128
li, err := d.Resource(gvrEndpoint).Namespace(corev1.NamespaceAll).List(ctx, metav1.ListOptions{})
148129
if err != nil {
149130
return nil, err
150131
}
151132

152-
ret := make(map[int]string)
133+
ret := make(map[int][]*unstructured.Unstructured)
153134
for _, ep := range li.Items {
154-
identity, ok, err := unstructured.NestedInt64(ep.Object, "status", "identity", "id")
135+
identity64, ok, err := unstructured.NestedInt64(ep.Object, "status", "identity", "id")
136+
identity := int(identity64)
155137
if err != nil {
156138
return nil, err
157139
}
158140
if !ok {
159141
continue
160142
}
161-
if _, ok := ret[int(identity)]; ok {
162-
ret[int(identity)] += "," + ep.GetName()
163-
} else {
164-
ret[int(identity)] = ep.GetName()
165-
}
143+
ret[identity] = append(ret[identity], &ep)
166144
}
167-
for k, v := range ret {
168-
if strings.Contains(v, ",") {
169-
samples := strings.Split(v, ",")
170-
i := rand.Intn(len(samples))
171-
ret[k] = samples[i]
145+
return ret, nil
146+
}
147+
148+
func writeSimpleOrJson(w io.Writer, content any, header []string, count int, values func(index int) []any) error {
149+
switch rootOptions.output {
150+
case OutputJson:
151+
text, err := json.MarshalIndent(content, "", " ")
152+
if err != nil {
153+
return err
154+
}
155+
_, err = w.Write(text)
156+
if err != nil {
157+
return err
158+
}
159+
_, err = w.Write([]byte{'\n'})
160+
return err
161+
case OutputSimple:
162+
tw := tabwriter.NewWriter(w, 0, 1, 1, ' ', 0)
163+
if !rootOptions.noHeaders {
164+
if _, err := tw.Write([]byte(strings.Join(header, "\t") + "\n")); err != nil {
165+
return err
166+
}
172167
}
168+
for i := range count {
169+
format := strings.Repeat("%v\t", len(header)-1) + "%v\n"
170+
if _, err := tw.Write([]byte(fmt.Sprintf(format, values(i)...))); err != nil {
171+
return err
172+
}
173+
}
174+
return tw.Flush()
175+
default:
176+
return fmt.Errorf("unknown format: %s", rootOptions.output)
173177
}
174-
return ret, nil
175178
}

cmd/npv/app/id_label.go

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,11 @@ package app
22

33
import (
44
"context"
5-
"encoding/json"
6-
"fmt"
75
"io"
86
"maps"
97
"slices"
108
"sort"
119
"strings"
12-
"text/tabwriter"
1310

1411
"github.com/spf13/cobra"
1512
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -80,29 +77,9 @@ func runIdLabel(ctx context.Context, w io.Writer) error {
8077
keys := slices.Collect(maps.Keys(labelMap))
8178
sort.Strings(keys)
8279

83-
switch rootOptions.output {
84-
case OutputJson:
85-
text, err := json.MarshalIndent(labelMap, "", " ")
86-
if err != nil {
87-
return err
88-
}
89-
_, err = w.Write(text)
90-
return err
91-
case OutputSimple:
92-
tw := tabwriter.NewWriter(w, 0, 1, 1, ' ', 0)
93-
if !rootOptions.noHeaders {
94-
if _, err := tw.Write([]byte("LABEL\tCOUNT\tVALUES\n")); err != nil {
95-
return err
96-
}
97-
}
98-
for _, k := range keys {
99-
li := labelMap[k]
100-
if _, err := tw.Write([]byte(fmt.Sprintf("%v\t%v\t%v\n", k, len(li), strings.Join(li, ",")))); err != nil {
101-
return err
102-
}
103-
}
104-
return tw.Flush()
105-
default:
106-
return fmt.Errorf("unknown format: %s", rootOptions.output)
107-
}
80+
return writeSimpleOrJson(w, labelMap, []string{"LABEL", "COUNT", "VALUES"}, len(keys), func(index int) []any {
81+
k := keys[index]
82+
li := labelMap[k]
83+
return []any{k, len(li), strings.Join(li, ",")}
84+
})
10885
}

cmd/npv/app/id_summary.go

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@ package app
22

33
import (
44
"context"
5-
"encoding/json"
6-
"fmt"
75
"io"
86
"maps"
97
"slices"
108
"sort"
11-
"text/tabwriter"
129

1310
"github.com/spf13/cobra"
1411
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -56,28 +53,8 @@ func runIdSummary(ctx context.Context, w io.Writer) error {
5653
keys := slices.Collect(maps.Keys(countMap))
5754
sort.Strings(keys)
5855

59-
switch rootOptions.output {
60-
case OutputJson:
61-
text, err := json.MarshalIndent(countMap, "", " ")
62-
if err != nil {
63-
return err
64-
}
65-
_, err = w.Write(text)
66-
return err
67-
case OutputSimple:
68-
tw := tabwriter.NewWriter(w, 0, 1, 1, ' ', 0)
69-
if !rootOptions.noHeaders {
70-
if _, err := tw.Write([]byte("NAMESPACE\tIDENTITY\n")); err != nil {
71-
return err
72-
}
73-
}
74-
for _, k := range keys {
75-
if _, err := tw.Write([]byte(fmt.Sprintf("%v\t%v\n", k, countMap[k]))); err != nil {
76-
return err
77-
}
78-
}
79-
return tw.Flush()
80-
default:
81-
return fmt.Errorf("unknown format: %s", rootOptions.output)
82-
}
56+
return writeSimpleOrJson(w, countMap, []string{"NAMESPACE", "IDENTITY"}, len(keys), func(index int) []any {
57+
k := keys[index]
58+
return []any{k, countMap[k]}
59+
})
8360
}

cmd/npv/app/inspect.go

Lines changed: 19 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import (
99
"slices"
1010
"strconv"
1111
"strings"
12-
"text/tabwriter"
1312

1413
"github.com/cilium/cilium/api/v1/client/policy"
1514
"github.com/cilium/cilium/pkg/identity"
1615
"github.com/cilium/cilium/pkg/u8proto"
1716
"github.com/spf13/cobra"
17+
"golang.org/x/exp/rand"
1818
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1919
"k8s.io/client-go/dynamic"
2020
"k8s.io/client-go/kubernetes"
@@ -135,7 +135,7 @@ func runInspect(ctx context.Context, w io.Writer, name string) error {
135135
return err
136136
}
137137

138-
examples, err := getIdentityExampleMap(ctx, dynamicClient)
138+
idEndpoints, err := getIdentityEndpoints(ctx, dynamicClient)
139139
if err != nil {
140140
return err
141141
}
@@ -164,8 +164,9 @@ func runInspect(ctx context.Context, w io.Writer, name string) error {
164164
}
165165
}
166166
entry.Example = "-"
167-
if v, ok := examples[p.Key.Identity]; ok {
168-
entry.Example = v
167+
if v, ok := idEndpoints[p.Key.Identity]; ok {
168+
i := rand.Intn(len(v))
169+
entry.Example = v[i].GetName()
169170
} else {
170171
idObj := identity.NumericIdentity(p.Key.Identity)
171172
if idObj.IsReservedIdentity() {
@@ -209,39 +210,20 @@ func runInspect(ctx context.Context, w io.Writer, name string) error {
209210
}
210211

211212
// I don't know it is safe to sort the result of "cilium bpf policy get", so let's keep the original order.
212-
switch rootOptions.output {
213-
case OutputJson:
214-
text, err := json.MarshalIndent(arr, "", " ")
215-
if err != nil {
216-
return err
217-
}
218-
_, err = w.Write(text)
219-
return err
220-
case OutputSimple:
221-
tw := tabwriter.NewWriter(w, 0, 1, 1, ' ', 0)
222-
if !rootOptions.noHeaders {
223-
if _, err := tw.Write([]byte("POLICY\tDIRECTION\tIDENTITY\tNAMESPACE\tEXAMPLE\tPROTOCOL\tPORT\tBYTES\tPACKETS\n")); err != nil {
224-
return err
225-
}
213+
header := []string{"POLICY", "DIRECTION", "IDENTITY", "NAMESPACE", "EXAMPLE", "PROTOCOL", "PORT", "BYTES", "PACKETS"}
214+
return writeSimpleOrJson(w, arr, header, len(arr), func(index int) []any {
215+
p := arr[index]
216+
var protocol, port string
217+
if p.WildcardProtocol {
218+
protocol = "ANY"
219+
} else {
220+
protocol = u8proto.U8proto(p.Protocol).String()
226221
}
227-
for _, p := range arr {
228-
var protocol, port string
229-
if p.WildcardProtocol {
230-
protocol = "ANY"
231-
} else {
232-
protocol = u8proto.U8proto(p.Protocol).String()
233-
}
234-
if p.WildcardPort {
235-
port = "ANY"
236-
} else {
237-
port = strconv.Itoa(p.Port)
238-
}
239-
if _, err := tw.Write([]byte(fmt.Sprintf("%v\t%v\t%v\t%v\t%v\t%v\t%v\t%v\t%v\n", p.Policy, p.Direction, p.Identity, p.Namespace, p.Example, protocol, port, p.Bytes, p.Packets))); err != nil {
240-
return err
241-
}
222+
if p.WildcardPort {
223+
port = "ANY"
224+
} else {
225+
port = strconv.Itoa(p.Port)
242226
}
243-
return tw.Flush()
244-
default:
245-
return fmt.Errorf("unknown format: %s", rootOptions.output)
246-
}
227+
return []any{p.Policy, p.Direction, p.Identity, p.Namespace, p.Example, protocol, port, p.Bytes, p.Packets}
228+
})
247229
}

0 commit comments

Comments
 (0)