Skip to content
This repository was archived by the owner on Mar 16, 2024. It is now read-only.

Commit 48faa3f

Browse files
authored
Add basic acorn events subcommand (#1562) (#1604)
* Add public and private API types for acorn events * Add aggregated API server for acorn events * Emit initial set of App related events * Add basic events subcommand and client * Generate basic acorn events docs * Add event unit tests for app image pull handler Signed-off-by: Nick Hale <[email protected]>
1 parent f16907b commit 48faa3f

39 files changed

+1803
-17
lines changed

docs/docs/100-reference/01-command-line/acorn.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ acorn [flags]
3333
* [acorn container](acorn_container.md) - Manage containers
3434
* [acorn credential](acorn_credential.md) - Manage registry credentials
3535
* [acorn dev](acorn_dev.md) - Run an app from an image or Acornfile in dev mode or attach a dev session to a currently running app
36+
* [acorn events](acorn_events.md) - List events about Acorn resources
3637
* [acorn exec](acorn_exec.md) - Run a command in a container
3738
* [acorn fmt](acorn_fmt.md) - Format an Acornfile
3839
* [acorn image](acorn_image.md) - Manage images
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
title: "acorn events"
3+
---
4+
## acorn events
5+
6+
List events about Acorn resources
7+
8+
```
9+
acorn events [flags]
10+
```
11+
12+
### Examples
13+
14+
```
15+
# List all events in the current project
16+
acorn events
17+
18+
# List events across all projects
19+
acorn -A events
20+
21+
# List the last 10 events
22+
acorn events --tail 10
23+
24+
# Getting Details
25+
# The 'details' field provides additional information about an event.
26+
# By default, this field is elided from this command's output, but can be enabled via the '--details' flag.
27+
acorn events --details
28+
29+
```
30+
31+
### Options
32+
33+
```
34+
-d, --details Don't strip event details from response
35+
-h, --help help for events
36+
-o, --output string Output format (json, yaml, {{gotemplate}})
37+
-t, --tail int Return this number of latest events
38+
```
39+
40+
### Options inherited from parent commands
41+
42+
```
43+
-A, --all-projects Use all known projects
44+
--debug Enable debug logging
45+
--debug-level int Debug log level (valid 0-9) (default 7)
46+
--kubeconfig string Explicitly use kubeconfig file, overriding current project
47+
-j, --project string Project to work in
48+
```
49+
50+
### SEE ALSO
51+
52+
* [acorn](acorn.md) -
53+

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ require (
5353
github.com/spf13/pflag v1.0.5
5454
github.com/stretchr/testify v1.8.1
5555
github.com/tonistiigi/fsutil v0.0.0-20220315205639-9ed612626da3
56+
github.com/wI2L/jsondiff v0.3.0
5657
golang.org/x/crypto v0.6.0
5758
golang.org/x/exp v0.0.0-20221114191408-850992195362
5859
golang.org/x/sync v0.1.0
@@ -249,6 +250,9 @@ require (
249250
github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 // indirect
250251
github.com/thales-e-security/pool v0.0.2 // indirect
251252
github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 // indirect
253+
github.com/tidwall/gjson v1.14.3 // indirect
254+
github.com/tidwall/match v1.1.1 // indirect
255+
github.com/tidwall/pretty v1.2.1 // indirect
252256
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
253257
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
254258
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect

go.sum

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1307,8 +1307,14 @@ github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gt
13071307
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
13081308
github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4 h1:1i/Afw3rmaR1gF3sfVkG2X6ldkikQwA9zY380LrR5YI=
13091309
github.com/theupdateframework/go-tuf v0.5.2-0.20220930112810-3890c1e7ace4/go.mod h1:vAqWV3zEs89byeFsAYoh/Q14vJTgJkHwnnRCWBBBINY=
1310+
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
1311+
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
1312+
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
1313+
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
13101314
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
1311-
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
1315+
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
1316+
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
1317+
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
13121318
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0=
13131319
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs=
13141320
github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
@@ -1342,6 +1348,8 @@ github.com/vbatts/tar-split v0.11.2 h1:Via6XqJr0hceW4wff3QRzD5gAk/tatMw/4ZA7cTlI
13421348
github.com/vbatts/tar-split v0.11.2/go.mod h1:vV3ZuO2yWSVsz+pfFzDG/upWH1JhjOiEaWq6kXyQ3VI=
13431349
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
13441350
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
1351+
github.com/wI2L/jsondiff v0.3.0 h1:iTzQ9u/d86GE9RsBzVHX88f2EA1vQUboHwLhSQFc1s4=
1352+
github.com/wI2L/jsondiff v0.3.0/go.mod h1:y1IMzNNjlSsk3IUoJdRJO7VRBtzMvRgyo4Vu0LdHpTc=
13451353
github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug=
13461354
github.com/xanzy/go-gitlab v0.73.1 h1:UMagqUZLJdjss1SovIC+kJCH4k2AZWXl58gJd38Y/hI=
13471355
github.com/xanzy/go-gitlab v0.73.1/go.mod h1:d/a0vswScO7Agg1CZNz15Ic6SSvBG9vfw8egL99t4kA=

integration/events/events_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package events
2+
3+
import (
4+
"testing"
5+
6+
"github.com/acorn-io/acorn/integration/helper"
7+
apiv1 "github.com/acorn-io/acorn/pkg/apis/api.acorn.io/v1"
8+
v1 "github.com/acorn-io/acorn/pkg/apis/internal.acorn.io/v1"
9+
"github.com/acorn-io/acorn/pkg/client"
10+
"github.com/acorn-io/acorn/pkg/server/registry/apigroups/acorn/apps"
11+
"github.com/stretchr/testify/assert"
12+
"github.com/stretchr/testify/require"
13+
)
14+
15+
func TestAppEvents(t *testing.T) {
16+
helper.StartController(t)
17+
18+
ctx := helper.GetCTX(t)
19+
c, ns := helper.ClientAndNamespace(t)
20+
21+
image, err := c.AcornImageBuild(ctx, "./testdata/simple/Acornfile", &client.AcornImageBuildOptions{
22+
Cwd: "./testdata/simple",
23+
})
24+
if err != nil {
25+
t.Fatal(err)
26+
}
27+
28+
// Create the app to generate an AppCreateEvent
29+
app, err := c.AppRun(ctx, image.ID, nil)
30+
if err != nil {
31+
t.Fatal(err)
32+
}
33+
34+
app = helper.WaitForObject(t, helper.Watcher(t, c), &apiv1.AppList{}, app, func(obj *apiv1.App) bool {
35+
return obj.Status.Condition(v1.AppInstanceConditionParsed).Success
36+
})
37+
assert.NotEmpty(t, app.Status.Namespace)
38+
39+
// Update the app spec to generate an AppSpecUpdatedEvent
40+
kc, err := c.GetClient()
41+
require.NoError(t, err)
42+
43+
stop := true
44+
app = helper.WaitForObject(t, helper.Watcher(t, c), &apiv1.AppList{}, app, func(obj *apiv1.App) bool {
45+
obj.Spec.Stop = &stop
46+
return kc.Update(ctx, obj) == nil
47+
})
48+
49+
// Delete the app to generate an AppDeletedEvent
50+
assert.NoError(t, kc.Delete(ctx, app))
51+
52+
// Ensure an event of each type has been recorded
53+
var created, updated, deleted bool
54+
helper.Wait(t, helper.Watcher(t, c), &apiv1.EventList{}, func(obj *apiv1.Event) bool {
55+
if obj.Namespace != ns.Name || obj.Source.Kind != "app" || obj.Source.Name != app.Name {
56+
// This event isn't for our app
57+
return false
58+
}
59+
60+
switch obj.Type {
61+
case apps.AppCreateEventType:
62+
created = true
63+
case apps.AppSpecUpdateEventType:
64+
updated = true
65+
case apps.AppDeleteEventType:
66+
deleted = true
67+
}
68+
69+
return created && updated && deleted
70+
})
71+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
containers: {
2+
simple: {
3+
build: "."
4+
}
5+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM ghcr.io/acorn-io/images-mirror/nginx:latest

pkg/apis/api.acorn.io/v1/scheme.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package v1
22

33
import (
4+
"fmt"
45
"net/url"
56

67
api_acorn_io "github.com/acorn-io/acorn/pkg/apis/api.acorn.io"
@@ -62,6 +63,8 @@ func AddToSchemeWithGV(scheme *runtime.Scheme, schemeGroupVersion schema.GroupVe
6263
&RegionList{},
6364
&ImageAllowRule{},
6465
&ImageAllowRuleList{},
66+
&Event{},
67+
&EventList{},
6568
)
6669

6770
// Add common types
@@ -77,7 +80,21 @@ func AddToSchemeWithGV(scheme *runtime.Scheme, schemeGroupVersion schema.GroupVe
7780
if err := scheme.AddConversionFunc((*url.Values)(nil), (*ContainerReplicaExecOptions)(nil), Convert_url_Values_To__ContainerReplicaExecOptions); err != nil {
7881
return err
7982
}
80-
return scheme.AddConversionFunc((*url.Values)(nil), (*LogOptions)(nil), Convert_url_Values_To__LogOptions)
83+
if err := scheme.AddConversionFunc((*url.Values)(nil), (*LogOptions)(nil), Convert_url_Values_To__LogOptions); err != nil {
84+
return err
85+
}
86+
87+
gvk := schemeGroupVersion.WithKind("Event")
88+
flcf := func(label, value string) (string, string, error) {
89+
switch label {
90+
case "details":
91+
return label, value, nil
92+
}
93+
return "", "", fmt.Errorf("unsupported field selection [%s]", label)
94+
}
95+
if err := scheme.AddFieldLabelConversionFunc(gvk, flcf); err != nil {
96+
return err
97+
}
8198
}
8299

83100
return nil

pkg/apis/api.acorn.io/v1/types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,3 +559,15 @@ type ImageAllowRuleList struct {
559559
metav1.ListMeta `json:"metadata,omitempty"`
560560
Items []ImageAllowRule `json:"items"`
561561
}
562+
563+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
564+
565+
type Event v1.EventInstance
566+
567+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
568+
569+
type EventList struct {
570+
metav1.TypeMeta `json:",inline"`
571+
metav1.ListMeta `json:"metadata,omitempty"`
572+
Items []Event `json:"items"`
573+
}

pkg/apis/api.acorn.io/v1/zz_generated.deepcopy.go

Lines changed: 60 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package v1
2+
3+
import (
4+
"fmt"
5+
6+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
7+
"k8s.io/apimachinery/pkg/types"
8+
)
9+
10+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
11+
12+
type EventInstanceList struct {
13+
metav1.TypeMeta `json:",inline"`
14+
metav1.ListMeta `json:"metadata,omitempty"`
15+
Items []EventInstance `json:"items"`
16+
}
17+
18+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
19+
20+
type EventInstance struct {
21+
metav1.TypeMeta `json:",inline"`
22+
metav1.ObjectMeta `json:"metadata,omitempty"`
23+
24+
// Type is a short, machine-readable string that describes the kind of Event that took place.
25+
Type string `json:"type"`
26+
27+
// Severity indicates the severity of the event.
28+
// +optional
29+
Severity EventSeverity `json:"severity,omitempty"`
30+
31+
// Actor is the ID of the entity that generated the Event.
32+
// This can be the name of a particular user or controller.
33+
Actor string `json:"actor"`
34+
35+
// Source identifies the object the Event is regarding.
36+
Source EventSource `json:"source"`
37+
38+
// Description is a human-readable description of the Event.
39+
// +optional
40+
Description string `json:"description,omitempty"`
41+
42+
// Observed represents the time the Event was first observed.
43+
Observed metav1.Time `json:"observed"`
44+
45+
// Details provides additional information about the cluster at the time the Event occurred.
46+
//
47+
// It's typically used to embed the subject resource, in its entirety, at the time the Event occurred,
48+
// but can be used to hold any data related to the event.
49+
//
50+
// +optional
51+
Details GenericMap `json:"details,omitempty"`
52+
}
53+
54+
const (
55+
EventSeverityInfo EventSeverity = "info"
56+
EventSeverityWarn EventSeverity = "warn"
57+
)
58+
59+
// EventSeverity indicates the severity of an event.
60+
type EventSeverity string
61+
62+
// EventSource identifies an object related to an Event.
63+
//
64+
// The referenced object may or may not exist.
65+
//
66+
// Note: corev1.ObjectReference was explicitly avoided because its use in new schemas is discouraged.
67+
// See https://github.com/kubernetes/api/blob/cdff1d4efea5d7ddc52c4085f82748c5f3e5cc8e/core/v1/types.go#L5919
68+
// for more details.
69+
type EventSource struct {
70+
// Kind is the source object kind.
71+
Kind string `json:"kind"`
72+
73+
// Name is the name of the source object.
74+
Name string `json:"name"`
75+
76+
// UID uniquely identifies the source object.
77+
UID types.UID `json:"uuid"`
78+
}
79+
80+
func (e EventSource) String() string {
81+
return fmt.Sprintf("%s/%s", e.Kind, e.Name)
82+
}

0 commit comments

Comments
 (0)