Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit042a5e2

Browse files
committed
chore: move usage types to new package
1 parent89b1757 commit042a5e2

File tree

13 files changed

+453
-188
lines changed

13 files changed

+453
-188
lines changed

‎coderd/database/modelmethods.go‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"encoding/hex"
55
"sort"
66
"strconv"
7-
"strings"
87
"time"
98

109
"github.com/google/uuid"
@@ -629,11 +628,3 @@ func (m WorkspaceAgentVolumeResourceMonitor) Debounce(
629628

630629
returnm.DebouncedUntil,false
631630
}
632-
633-
func (eUsageEventType)IsDiscrete()bool {
634-
returne.Valid()&&strings.HasPrefix(string(e),"dc_")
635-
}
636-
637-
func (eUsageEventType)IsHeartbeat()bool {
638-
returne.Valid()&&strings.HasPrefix(string(e),"hb_")
639-
}

‎coderd/provisionerdserver/provisionerdserver.go‎

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,6 @@ import (
2828
protobuf"google.golang.org/protobuf/proto"
2929

3030
"cdr.dev/slog"
31-
32-
"github.com/coder/coder/v2/coderd/usage"
33-
"github.com/coder/coder/v2/coderd/util/slice"
34-
35-
"github.com/coder/coder/v2/codersdk/drpcsdk"
36-
37-
"github.com/coder/quartz"
38-
3931
"github.com/coder/coder/v2/coderd/apikey"
4032
"github.com/coder/coder/v2/coderd/audit"
4133
"github.com/coder/coder/v2/coderd/database"
@@ -49,13 +41,18 @@ import (
4941
"github.com/coder/coder/v2/coderd/schedule"
5042
"github.com/coder/coder/v2/coderd/telemetry"
5143
"github.com/coder/coder/v2/coderd/tracing"
44+
"github.com/coder/coder/v2/coderd/usage"
45+
"github.com/coder/coder/v2/coderd/usage/usagetypes"
46+
"github.com/coder/coder/v2/coderd/util/slice"
5247
"github.com/coder/coder/v2/coderd/wspubsub"
5348
"github.com/coder/coder/v2/codersdk"
5449
"github.com/coder/coder/v2/codersdk/agentsdk"
50+
"github.com/coder/coder/v2/codersdk/drpcsdk"
5551
"github.com/coder/coder/v2/provisioner"
5652
"github.com/coder/coder/v2/provisionerd/proto"
5753
"github.com/coder/coder/v2/provisionersdk"
5854
sdkproto"github.com/coder/coder/v2/provisionersdk/proto"
55+
"github.com/coder/quartz"
5956
)
6057

6158
const (
@@ -1903,7 +1900,7 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
19031900
// Collect usage event for managed agents.
19041901
usageCollector:=s.UsageCollector.Load()
19051902
ifusageCollector!=nil {
1906-
event:=usage.DCManagedAgentsV1{
1903+
event:=usagetypes.DCManagedAgentsV1{
19071904
Count:1,
19081905
}
19091906
err= (*usageCollector).CollectDiscreteUsageEvent(ctx,db,event)

‎coderd/provisionerdserver/provisionerdserver_test.go‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import (
4545
"github.com/coder/coder/v2/coderd/schedule/cron"
4646
"github.com/coder/coder/v2/coderd/telemetry"
4747
"github.com/coder/coder/v2/coderd/usage"
48+
"github.com/coder/coder/v2/coderd/usage/usagetypes"
4849
"github.com/coder/coder/v2/coderd/wspubsub"
4950
"github.com/coder/coder/v2/codersdk"
5051
"github.com/coder/coder/v2/codersdk/agentsdk"
@@ -2678,7 +2679,7 @@ func TestCompleteJob(t *testing.T) {
26782679

26792680
// Check that a usage event was collected.
26802681
require.Len(t,fakeUsageCollector.collectedEvents,1)
2681-
require.Equal(t,usage.DCManagedAgentsV1{
2682+
require.Equal(t,usagetypes.DCManagedAgentsV1{
26822683
Count:1,
26832684
},fakeUsageCollector.collectedEvents[0])
26842685
}else {
@@ -3850,7 +3851,7 @@ func (s *fakeStream) cancel() {
38503851
}
38513852

38523853
typefakeUsageCollectorstruct {
3853-
collectedEvents []usage.Event
3854+
collectedEvents []usagetypes.Event
38543855
}
38553856

38563857
var_ usage.Collector=&fakeUsageCollector{}
@@ -3863,7 +3864,7 @@ func newFakeUsageCollector() (*fakeUsageCollector, *atomic.Pointer[usage.Collect
38633864
returnfake,ptr
38643865
}
38653866

3866-
func (f*fakeUsageCollector)CollectDiscreteUsageEvent(_ context.Context,_ database.Store,eventusage.DiscreteEvent)error {
3867+
func (f*fakeUsageCollector)CollectDiscreteUsageEvent(_ context.Context,_ database.Store,eventusagetypes.DiscreteEvent)error {
38673868
f.collectedEvents=append(f.collectedEvents,event)
38683869
returnnil
38693870
}

‎coderd/usage/collector.go‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ import (
44
"context"
55

66
"github.com/coder/coder/v2/coderd/database"
7+
"github.com/coder/coder/v2/coderd/usage/usagetypes"
78
)
89

910
// Collector is a sink for usage events generated by the product.
1011
typeCollectorinterface {
1112
// CollectDiscreteUsageEvent writes a discrete usage event to the database
1213
// with the given database or transaction.
13-
CollectDiscreteUsageEvent(ctx context.Context,db database.Store,eventDiscreteEvent)error
14+
CollectDiscreteUsageEvent(ctx context.Context,db database.Store,eventusagetypes.DiscreteEvent)error
1415
}
1516

1617
// AGPLCollector is a no-op implementation of Collector.
@@ -24,6 +25,6 @@ func NewAGPLCollector() Collector {
2425

2526
// CollectDiscreteUsageEvent is a no-op implementation of
2627
// CollectDiscreteUsageEvent.
27-
func (AGPLCollector)CollectDiscreteUsageEvent(_ context.Context,_ database.Store,_DiscreteEvent)error {
28+
func (AGPLCollector)CollectDiscreteUsageEvent(_ context.Context,_ database.Store,_usagetypes.DiscreteEvent)error {
2829
returnnil
2930
}

‎coderd/usage/events.go‎

Lines changed: 0 additions & 47 deletions
This file was deleted.

‎coderd/usage/usagetypes/events.go‎

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Package usagetypes contains the types for usage events. These are kept in
2+
// their own package to avoid importing any real code from coderd.
3+
//
4+
// Imports in this package should be limited to the standard library and the
5+
// following packages ONLY:
6+
// - github.com/google/uuid
7+
// - golang.org/x/xerrors
8+
//
9+
// This package is imported by the Tallyman codebase.
10+
package usagetypes
11+
12+
// Please read the package documentation before adding imports.
13+
import (
14+
"bytes"
15+
"encoding/json"
16+
"strings"
17+
18+
"golang.org/x/xerrors"
19+
)
20+
21+
// UsageEventType is an enum of all usage event types. It mirrors the database
22+
// type `usage_event_type`.
23+
typeUsageEventTypestring
24+
25+
const (
26+
UsageEventTypeDCManagedAgentsV1UsageEventType="dc_managed_agents_v1"
27+
)
28+
29+
func (eUsageEventType)Valid()bool {
30+
switche {
31+
caseUsageEventTypeDCManagedAgentsV1:
32+
returntrue
33+
default:
34+
returnfalse
35+
}
36+
}
37+
38+
func (eUsageEventType)IsDiscrete()bool {
39+
returne.Valid()&&strings.HasPrefix(string(e),"dc_")
40+
}
41+
42+
func (eUsageEventType)IsHeartbeat()bool {
43+
returne.Valid()&&strings.HasPrefix(string(e),"hb_")
44+
}
45+
46+
// ParseEvent parses the raw event data into the specified Go type. It fails if
47+
// there is any unknown fields or extra data after the event. The returned event
48+
// is validated.
49+
funcParseEvent[TEvent](data json.RawMessage) (T,error) {
50+
dec:=json.NewDecoder(bytes.NewReader(data))
51+
dec.DisallowUnknownFields()
52+
53+
vareventT
54+
err:=dec.Decode(&event)
55+
iferr!=nil {
56+
returnevent,xerrors.Errorf("unmarshal %T event: %w",event,err)
57+
}
58+
ifdec.More() {
59+
returnevent,xerrors.Errorf("extra data after %T event",event)
60+
}
61+
err=event.Valid()
62+
iferr!=nil {
63+
returnevent,xerrors.Errorf("invalid %T event: %w",event,err)
64+
}
65+
66+
returnevent,nil
67+
}
68+
69+
// ParseEventWithType parses the raw event data into the specified Go type. It
70+
// fails if there is any unknown fields or extra data after the event. The
71+
// returned event is validated.
72+
funcParseEventWithType(eventTypeUsageEventType,data json.RawMessage) (Event,error) {
73+
switcheventType {
74+
caseUsageEventTypeDCManagedAgentsV1:
75+
returnParseEvent[DCManagedAgentsV1](data)
76+
default:
77+
returnnil,xerrors.Errorf("unknown event type: %s",eventType)
78+
}
79+
}
80+
81+
// Event is a usage event that can be collected by the usage collector.
82+
//
83+
// Note that the following event types should not be updated once they are
84+
// merged into the product. Please consult Dean before making any changes.
85+
typeEventinterface {
86+
usageEvent()// to prevent external types from implementing this interface
87+
EventType()UsageEventType
88+
Valid()error
89+
}
90+
91+
// DiscreteEvent is a usage event that is collected as a discrete event.
92+
typeDiscreteEventinterface {
93+
Event
94+
discreteUsageEvent()// marker method, also prevents external types from implementing this interface
95+
}
96+
97+
// DCManagedAgentsV1 is a discrete usage event for the number of managed agents.
98+
// This event is sent in the following situations:
99+
// - Once on first startup after usage tracking is added to the product with
100+
// the count of all existing managed agents (count=N)
101+
// - A new managed agent is created (count=1)
102+
typeDCManagedAgentsV1struct {
103+
Countuint64`json:"count"`
104+
}
105+
106+
var_DiscreteEvent=DCManagedAgentsV1{}
107+
108+
func (DCManagedAgentsV1)usageEvent() {}
109+
func (DCManagedAgentsV1)discreteUsageEvent() {}
110+
func (DCManagedAgentsV1)EventType()UsageEventType {
111+
returnUsageEventTypeDCManagedAgentsV1
112+
}
113+
114+
func (eDCManagedAgentsV1)Valid()error {
115+
ife.Count==0 {
116+
returnxerrors.New("count must be greater than 0")
117+
}
118+
returnnil
119+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package usagetypes_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
8+
"github.com/coder/coder/v2/coderd/usage/usagetypes"
9+
)
10+
11+
funcTestParseEvent(t*testing.T) {
12+
t.Parallel()
13+
14+
t.Run("ExtraFields",func(t*testing.T) {
15+
t.Parallel()
16+
_,err:= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1, "extra": "field"}`))
17+
require.ErrorContains(t,err,"unmarshal usagetypes.DCManagedAgentsV1 event")
18+
})
19+
20+
t.Run("ExtraData",func(t*testing.T) {
21+
t.Parallel()
22+
_,err:= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1}{"count": 2}`))
23+
require.ErrorContains(t,err,"extra data after usagetypes.DCManagedAgentsV1 event")
24+
})
25+
26+
t.Run("DCManagedAgentsV1",func(t*testing.T) {
27+
t.Parallel()
28+
29+
event,err:= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": 1}`))
30+
require.NoError(t,err)
31+
require.Equal(t, usagetypes.DCManagedAgentsV1{Count:1},event)
32+
33+
_,err= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": "invalid"}`))
34+
require.ErrorContains(t,err,"unmarshal usagetypes.DCManagedAgentsV1 event")
35+
36+
_,err= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{}`))
37+
require.ErrorContains(t,err,"invalid usagetypes.DCManagedAgentsV1 event: count must be greater than 0")
38+
})
39+
}
40+
41+
funcTestParseEventWithType(t*testing.T) {
42+
t.Parallel()
43+
44+
t.Run("UnknownEvent",func(t*testing.T) {
45+
t.Parallel()
46+
_,err:=usagetypes.ParseEventWithType(usagetypes.UsageEventType("fake"), []byte(`{}`))
47+
require.ErrorContains(t,err,"unknown event type: fake")
48+
})
49+
50+
t.Run("DCManagedAgentsV1",func(t*testing.T) {
51+
t.Parallel()
52+
53+
eventType:=usagetypes.UsageEventTypeDCManagedAgentsV1
54+
event,err:=usagetypes.ParseEventWithType(eventType, []byte(`{"count": 1}`))
55+
require.NoError(t,err)
56+
require.Equal(t, usagetypes.DCManagedAgentsV1{Count:1},event)
57+
require.Equal(t,eventType,event.EventType())
58+
})
59+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp