Skip to content

Commit 7d1c606

Browse files
committed
Bootstrap initial state
1 parent 8cddb62 commit 7d1c606

File tree

8 files changed

+200
-85
lines changed

8 files changed

+200
-85
lines changed

go.mod

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ require (
66
cloud.google.com/go/logging v1.10.0
77
github.com/dgraph-io/badger/v4 v4.2.0
88
github.com/expr-lang/expr v1.16.9
9+
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
10+
golang.org/x/time v0.5.0
911
google.golang.org/genproto v0.0.0-20240708141625-4ad9e859172b
12+
google.golang.org/grpc v1.64.1
1013
gopkg.in/yaml.v3 v3.0.1
14+
k8s.io/apiextensions-apiserver v0.30.2
15+
k8s.io/apimachinery v0.30.2
1116
k8s.io/client-go v0.30.2
1217
)
1318

@@ -21,7 +26,7 @@ require (
2126
github.com/cespare/xxhash/v2 v2.2.0 // indirect
2227
github.com/davecgh/go-spew v1.1.1 // indirect
2328
github.com/dgraph-io/ristretto v0.1.1 // indirect
24-
github.com/dustin/go-humanize v1.0.0 // indirect
29+
github.com/dustin/go-humanize v1.0.1 // indirect
2530
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
2631
github.com/felixge/httpsnoop v1.0.4 // indirect
2732
github.com/go-logr/logr v1.4.1 // indirect
@@ -64,16 +69,13 @@ require (
6469
golang.org/x/sys v0.21.0 // indirect
6570
golang.org/x/term v0.21.0 // indirect
6671
golang.org/x/text v0.16.0 // indirect
67-
golang.org/x/time v0.5.0 // indirect
6872
google.golang.org/api v0.187.0 // indirect
6973
google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect
7074
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
71-
google.golang.org/grpc v1.64.1 // indirect
7275
google.golang.org/protobuf v1.34.2 // indirect
7376
gopkg.in/inf.v0 v0.9.1 // indirect
7477
gopkg.in/yaml.v2 v2.4.0 // indirect
7578
k8s.io/api v0.30.2 // indirect
76-
k8s.io/apimachinery v0.30.2 // indirect
7779
k8s.io/klog/v2 v2.120.1 // indirect
7880
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
7981
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect

go.sum

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa
3030
github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
3131
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
3232
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
33-
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
3433
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
34+
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
35+
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
3536
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
3637
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
3738
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -176,6 +177,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
176177
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
177178
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
178179
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
180+
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
181+
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
179182
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
180183
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
181184
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -278,6 +281,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
278281
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
279282
k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI=
280283
k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI=
284+
k8s.io/apiextensions-apiserver v0.30.2 h1:l7Eue2t6QiLHErfn2vwK4KgF4NeDgjQkCXtEbOocKIE=
285+
k8s.io/apiextensions-apiserver v0.30.2/go.mod h1:lsJFLYyK40iguuinsb3nt+Sj6CmodSI4ACDLep1rgjw=
281286
k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg=
282287
k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
283288
k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50=

internal/auditlog/tail.go

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,13 @@ import (
1616
"google.golang.org/grpc/status"
1717
)
1818

19-
var suspendableResourceNames = []string{
20-
"alerts",
21-
"buckets",
22-
"gitrepositories",
23-
"helmcharts",
24-
"helmreleases",
25-
"helmrepositories",
26-
"imagerepositories",
27-
"imageupdateautomations",
28-
"kustomizations",
29-
"ocirepositories",
30-
"providers",
31-
"receivers",
32-
}
33-
34-
func Tail(ctx context.Context, projectID, clusterName string, cb func(*audit.AuditLog) error) error {
19+
func Tail(
20+
ctx context.Context,
21+
projectID string,
22+
clusterName string,
23+
resourceKinds []string,
24+
cb func(*audit.AuditLog) error,
25+
) error {
3526
client, err := logging.NewClient(ctx)
3627
if err != nil {
3728
return fmt.Errorf("failed to create client: %w", err)
@@ -52,7 +43,7 @@ func Tail(ctx context.Context, projectID, clusterName string, cb func(*audit.Aud
5243
return fmt.Errorf("limit wait failed: %w", err)
5344
}
5445

55-
if err = tailLogs(ctx, client, projectID, clusterName, cb); err != nil {
46+
if err = tailLogs(ctx, client, projectID, clusterName, resourceKinds, cb); err != nil {
5647
if _, ok := status.FromError(err); ok {
5748
slog.Warn("gRPC request terminated, restarting", slog.Any("error", err))
5849
continue
@@ -62,7 +53,14 @@ func Tail(ctx context.Context, projectID, clusterName string, cb func(*audit.Aud
6253
}
6354
}
6455

65-
func tailLogs(ctx context.Context, client *logging.Client, projectID, clusterName string, cb func(*audit.AuditLog) error) error {
56+
func tailLogs(
57+
ctx context.Context,
58+
client *logging.Client,
59+
projectID string,
60+
clusterName string,
61+
resourceKinds []string,
62+
cb func(*audit.AuditLog) error,
63+
) error {
6664
stream, err := client.TailLogEntries(ctx)
6765
if err != nil {
6866
return fmt.Errorf("request to tail log entries failed: %w", err)
@@ -79,7 +77,7 @@ func tailLogs(ctx context.Context, client *logging.Client, projectID, clusterNam
7977
fmt.Sprintf(`log_name="projects/%s/logs/cloudaudit.googleapis.com%%2Factivity"`, projectID),
8078
fmt.Sprintf(`resource.labels.cluster_name="%s"`, clusterName),
8179
`protoPayload."@type"="type.googleapis.com/google.cloud.audit.AuditLog"`,
82-
fmt.Sprintf(`protoPayload.methodName=~"io\.fluxcd\.toolkit\..*\.(%s)\.patch"`, strings.Join(suspendableResourceNames, "|")),
80+
fmt.Sprintf(`protoPayload.methodName=~"io\.fluxcd\.toolkit\..*\.(%s)\.patch"`, strings.Join(resourceKinds, "|")),
8381
`-protoPayload.authenticationInfo.principalEmail=~"system:.*"`,
8482
},
8583
" AND ",

internal/datastore/badgerdb.go

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -69,34 +69,10 @@ func (s *Store) SaveEntry(entry Entry) error {
6969
})
7070
}
7171

72-
func (s *Store) AllEntries() ([]Entry, error) {
73-
entries := make([]Entry, 0)
74-
err := s.db.View(func(txn *badger.Txn) error {
75-
it := txn.NewIterator(badger.DefaultIteratorOptions)
76-
defer it.Close()
77-
78-
prefix := []byte("resource:")
79-
for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
80-
item := it.Item()
81-
val, err := item.ValueCopy(nil)
82-
if err != nil {
83-
return fmt.Errorf("failed to get value: %w", err)
84-
}
85-
var entry Entry
86-
if err = json.Unmarshal(val, &entry); err != nil {
87-
return fmt.Errorf("failed to unmarshal entry: %w", err)
88-
}
89-
entries = append(entries, entry)
90-
}
91-
return nil
92-
})
93-
return entries, err
94-
}
95-
9672
func (s *Store) Close() error {
9773
return s.db.Close()
9874
}
9975

10076
func buildKey(resource k8s.Resource) []byte {
101-
return []byte(fmt.Sprintf("resource:%s:%s:%s", resource.Kind, resource.Namespace, resource.Name))
77+
return []byte(fmt.Sprintf("resource:%s:%s:%s:%s", resource.Type.Group, resource.Type.Kind, resource.Namespace, resource.Name))
10278
}

internal/k8s/client.go

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,17 @@ import (
77
"log/slog"
88
"path"
99

10+
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
11+
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
12+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1013
"k8s.io/client-go/kubernetes"
1114
"k8s.io/client-go/rest"
1215
"k8s.io/client-go/tools/clientcmd"
1316
)
1417

1518
type Client struct {
16-
client *kubernetes.Clientset
19+
client *kubernetes.Clientset
20+
apiExtClient *clientset.Clientset
1721
}
1822

1923
func NewClient(configPath string) (*Client, error) {
@@ -35,15 +39,31 @@ func NewClient(configPath string) (*Client, error) {
3539
return nil, err
3640
}
3741

42+
apiExtClientSet, err := clientset.NewForConfig(config)
43+
if err != nil {
44+
return nil, err
45+
}
46+
3847
return &Client{
39-
client: clientSet,
48+
client: clientSet,
49+
apiExtClient: apiExtClientSet,
4050
}, nil
4151
}
4252

43-
func (c *Client) GetRawResource(ctx context.Context, relativePath string) (map[string]any, error) {
44-
body, err := c.client.RESTClient().Get().AbsPath(path.Join("apis", relativePath)).DoRaw(ctx)
53+
func (c *Client) GetRawResource(ctx context.Context, resource Resource) (map[string]any, error) {
54+
absPath := path.Join(
55+
"apis",
56+
resource.Type.Group,
57+
resource.Type.Version,
58+
"namespaces",
59+
resource.Namespace,
60+
resource.Type.Kind,
61+
resource.Name,
62+
)
63+
64+
body, err := c.client.RESTClient().Get().AbsPath(absPath).DoRaw(ctx)
4565
if err != nil {
46-
slog.Warn("failed to fetch resource", slog.Any("error", err), slog.Any("path", path.Join("apis", relativePath)))
66+
slog.Warn("failed to fetch resource", slog.Any("error", err), slog.Any("path", absPath))
4767
return nil, err
4868
}
4969

@@ -53,3 +73,31 @@ func (c *Client) GetRawResource(ctx context.Context, relativePath string) (map[s
5373
}
5474
return res, nil
5575
}
76+
77+
func (c *Client) GetRawResources(ctx context.Context, group ResourceType) (map[string]any, error) {
78+
absPath := path.Join(
79+
"apis",
80+
group.Group,
81+
group.Version,
82+
group.Kind,
83+
)
84+
85+
body, err := c.client.RESTClient().Get().AbsPath(absPath).DoRaw(ctx)
86+
if err != nil {
87+
slog.Warn("failed to fetch resource", slog.Any("error", err), slog.Any("path", absPath))
88+
return nil, err
89+
}
90+
91+
var res map[string]any
92+
if err = json.Unmarshal(body, &res); err != nil {
93+
return nil, fmt.Errorf("invalid response: %w", err)
94+
}
95+
return res, nil
96+
}
97+
98+
func (c *Client) GetCustomResourceDefinitions(ctx context.Context, listOptions metav1.ListOptions) (*v1.CustomResourceDefinitionList, error) {
99+
return c.apiExtClient.
100+
ApiextensionsV1().
101+
CustomResourceDefinitions().
102+
List(ctx, listOptions)
103+
}

internal/k8s/resource.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,16 @@ import (
55
"strings"
66
)
77

8+
type ResourceType struct {
9+
Group string `json:"group"`
10+
Version string `json:"version"`
11+
Kind string `json:"kind"`
12+
}
13+
814
type Resource struct {
9-
Namespace string
10-
Kind string
11-
Name string
12-
Path string
15+
Type ResourceType `json:"type"`
16+
Namespace string `json:"namespace"`
17+
Name string `json:"name"`
1318
}
1419

1520
func ResourceFromPath(path string) (Resource, error) {
@@ -18,9 +23,12 @@ func ResourceFromPath(path string) (Resource, error) {
1823
return Resource{}, fmt.Errorf("unexpected path format: %s", path)
1924
}
2025
return Resource{
26+
Type: ResourceType{
27+
Group: parts[0],
28+
Version: parts[1],
29+
Kind: parts[4],
30+
},
2131
Namespace: parts[3],
22-
Kind: strings.TrimSuffix(parts[4], "s"),
2332
Name: parts[5],
24-
Path: path,
2533
}, nil
2634
}

internal/notification/slack.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"errors"
88
"fmt"
99
"net/http"
10+
"strings"
1011
"time"
1112
)
1213

@@ -58,11 +59,13 @@ func (sn *SlackNotifier) Notify(ctx context.Context, notif Notification) error {
5859
color = "good"
5960
}
6061

62+
kind := strings.TrimSuffix(notif.Resource.Type.Kind, "s")
63+
6164
reqBody, err := json.Marshal(SlackWebhook{
6265
Attachments: []SlackAttachment{
6366
{
6467
Color: color,
65-
AuthorName: fmt.Sprintf("%s/%s.%s", notif.Resource.Kind, notif.Resource.Name, notif.Resource.Namespace),
68+
AuthorName: fmt.Sprintf("%s/%s.%s", kind, notif.Resource.Name, notif.Resource.Namespace),
6669
Text: fmt.Sprintf("%s by %s", action, notif.Email),
6770
MrkdwnIn: []string{"text"},
6871
Fields: []SlackAttachmentField{

0 commit comments

Comments
 (0)