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

Commitfb89896

Browse files
committed
chore: move usage types to new package
1 parent397a84d commitfb89896

File tree

12 files changed

+470
-225
lines changed

12 files changed

+470
-225
lines changed

‎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 (
@@ -2037,7 +2034,7 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
20372034
// Insert usage event for managed agents.
20382035
usageInserter:=s.UsageInserter.Load()
20392036
ifusageInserter!=nil {
2040-
event:=usage.DCManagedAgentsV1{
2037+
event:=usagetypes.DCManagedAgentsV1{
20412038
Count:1,
20422039
}
20432040
err= (*usageInserter).InsertDiscreteUsageEvent(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"
@@ -2924,7 +2925,7 @@ func TestCompleteJob(t *testing.T) {
29242925

29252926
// Check that a usage event was collected.
29262927
require.Len(t,fakeUsageInserter.collectedEvents,1)
2927-
require.Equal(t,usage.DCManagedAgentsV1{
2928+
require.Equal(t,usagetypes.DCManagedAgentsV1{
29282929
Count:1,
29292930
},fakeUsageInserter.collectedEvents[0])
29302931
}else {
@@ -4102,7 +4103,7 @@ func (s *fakeStream) cancel() {
41024103
}
41034104

41044105
typefakeUsageInserterstruct {
4105-
collectedEvents []usage.Event
4106+
collectedEvents []usagetypes.Event
41064107
}
41074108

41084109
var_ usage.Inserter=&fakeUsageInserter{}
@@ -4115,7 +4116,7 @@ func newFakeUsageInserter() (*fakeUsageInserter, *atomic.Pointer[usage.Inserter]
41154116
returnfake,ptr
41164117
}
41174118

4118-
func (f*fakeUsageInserter)InsertDiscreteUsageEvent(_ context.Context,_ database.Store,eventusage.DiscreteEvent)error {
4119+
func (f*fakeUsageInserter)InsertDiscreteUsageEvent(_ context.Context,_ database.Store,eventusagetypes.DiscreteEvent)error {
41194120
f.collectedEvents=append(f.collectedEvents,event)
41204121
returnnil
41214122
}

‎coderd/usage/events.go‎

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

‎coderd/usage/inserter.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
// Inserter accepts usage events generated by the product.
1011
typeInserterinterface {
1112
// InsertDiscreteUsageEvent writes a discrete usage event to the database
1213
// within the given transaction.
13-
InsertDiscreteUsageEvent(ctx context.Context,tx database.Store,eventDiscreteEvent)error
14+
InsertDiscreteUsageEvent(ctx context.Context,tx database.Store,eventusagetypes.DiscreteEvent)error
1415
}
1516

1617
// AGPLInserter is a no-op implementation of Inserter.
@@ -24,6 +25,6 @@ func NewAGPLInserter() Inserter {
2425

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

‎coderd/usage/usagetypes/events.go‎

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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+
//
86+
// This type cannot be implemented outside of this package as it this package
87+
// is the source of truth for the coder/tallyman repo.
88+
typeEventinterface {
89+
usageEvent()// to prevent external types from implementing this interface
90+
EventType()UsageEventType
91+
Valid()error
92+
Fields()map[string]any// fields to be marshaled and sent to tallyman/Metronome
93+
}
94+
95+
// DiscreteEvent is a usage event that is collected as a discrete event.
96+
typeDiscreteEventinterface {
97+
Event
98+
discreteUsageEvent()// marker method, also prevents external types from implementing this interface
99+
}
100+
101+
// DCManagedAgentsV1 is a discrete usage event for the number of managed agents.
102+
// This event is sent in the following situations:
103+
// - Once on first startup after usage tracking is added to the product with
104+
// the count of all existing managed agents (count=N)
105+
// - A new managed agent is created (count=1)
106+
typeDCManagedAgentsV1struct {
107+
Countuint64`json:"count"`
108+
}
109+
110+
var_DiscreteEvent=DCManagedAgentsV1{}
111+
112+
func (DCManagedAgentsV1)usageEvent() {}
113+
func (DCManagedAgentsV1)discreteUsageEvent() {}
114+
func (DCManagedAgentsV1)EventType()UsageEventType {
115+
returnUsageEventTypeDCManagedAgentsV1
116+
}
117+
118+
func (eDCManagedAgentsV1)Valid()error {
119+
ife.Count==0 {
120+
returnxerrors.New("count must be greater than 0")
121+
}
122+
returnnil
123+
}
124+
125+
func (eDCManagedAgentsV1)Fields()map[string]any {
126+
returnmap[string]any{
127+
"count":e.Count,
128+
}
129+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
require.Equal(t,map[string]any{"count":uint64(1)},event.Fields())
33+
34+
_,err= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{"count": "invalid"}`))
35+
require.ErrorContains(t,err,"unmarshal usagetypes.DCManagedAgentsV1 event")
36+
37+
_,err= usagetypes.ParseEvent[usagetypes.DCManagedAgentsV1]([]byte(`{}`))
38+
require.ErrorContains(t,err,"invalid usagetypes.DCManagedAgentsV1 event: count must be greater than 0")
39+
})
40+
}
41+
42+
funcTestParseEventWithType(t*testing.T) {
43+
t.Parallel()
44+
45+
t.Run("UnknownEvent",func(t*testing.T) {
46+
t.Parallel()
47+
_,err:=usagetypes.ParseEventWithType(usagetypes.UsageEventType("fake"), []byte(`{}`))
48+
require.ErrorContains(t,err,"unknown event type: fake")
49+
})
50+
51+
t.Run("DCManagedAgentsV1",func(t*testing.T) {
52+
t.Parallel()
53+
54+
eventType:=usagetypes.UsageEventTypeDCManagedAgentsV1
55+
event,err:=usagetypes.ParseEventWithType(eventType, []byte(`{"count": 1}`))
56+
require.NoError(t,err)
57+
require.Equal(t, usagetypes.DCManagedAgentsV1{Count:1},event)
58+
require.Equal(t,eventType,event.EventType())
59+
require.Equal(t,map[string]any{"count":uint64(1)},event.Fields())
60+
})
61+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp