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

Commite999a58

Browse files
committed
Implement preset auto match
1 parentd3d8948 commite999a58

File tree

13 files changed

+680
-48
lines changed

13 files changed

+680
-48
lines changed

‎coderd/database/dbauthz/dbauthz.go‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,6 +1810,14 @@ func (q *querier) FetchVolumesResourceMonitorsUpdatedAfter(ctx context.Context,
18101810
returnq.db.FetchVolumesResourceMonitorsUpdatedAfter(ctx,updatedAt)
18111811
}
18121812

1813+
func (q*querier)FindMatchingPresetID(ctx context.Context,arg database.FindMatchingPresetIDParams) (uuid.UUID,error) {
1814+
_,err:=q.GetTemplateVersionByID(ctx,arg.TemplateVersionID)
1815+
iferr!=nil {
1816+
returnuuid.Nil,err
1817+
}
1818+
returnq.db.FindMatchingPresetID(ctx,arg)
1819+
}
1820+
18131821
func (q*querier)GetAPIKeyByID(ctx context.Context,idstring) (database.APIKey,error) {
18141822
returnfetch(q.log,q.auth,q.db.GetAPIKeyByID)(ctx,id)
18151823
}

‎coderd/database/dbauthz/dbauthz_test.go‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4959,6 +4959,13 @@ func (s *MethodTestSuite) TestPrebuilds() {
49594959
template,policy.ActionUse,
49604960
).Errors(sql.ErrNoRows)
49614961
}))
4962+
s.Run("FindMatchingPresetID",s.Subtest(func(db database.Store,check*expects) {
4963+
check.Args(database.FindMatchingPresetIDParams{
4964+
TemplateVersionID:uuid.New(),
4965+
ParameterNames: []string{"test"},
4966+
ParameterValues: []string{"test"},
4967+
}).Asserts(rbac.ResourceTemplate,policy.ActionRead)
4968+
}))
49624969
s.Run("GetPrebuildMetrics",s.Subtest(func(_ database.Store,check*expects) {
49634970
check.Args().
49644971
Asserts(rbac.ResourceWorkspace.All(),policy.ActionRead)

‎coderd/database/dbmetrics/querymetrics.go‎

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/dbmock/dbmock.go‎

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/querier.go‎

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries.sql.go‎

Lines changed: 40 additions & 0 deletions
Some generated files are not rendered by default. Learn more aboutcustomizing how changed files appear on GitHub.

‎coderd/database/queries/prebuilds.sql‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,29 @@ INNER JOIN organizations o ON o.id = w.organization_id
245245
WHERE NOTt.deletedANDwpb.build_number=1
246246
GROUP BYt.name,tvp.name,o.name
247247
ORDER BYt.name,tvp.name,o.name;
248+
249+
-- name: FindMatchingPresetID :one
250+
-- FindMatchingPresetID finds a preset ID that is the largest exact subset of the provided parameters.
251+
-- It returns the preset ID if a match is found, or NULL if no match is found.
252+
-- The query finds presets where all preset parameters are present in the provided parameters,
253+
-- and returns the preset with the most parameters (largest subset).
254+
WITH provided_paramsAS (
255+
SELECT unnest(@parameter_names::text[])AS name,
256+
unnest(@parameter_values::text[])AS value
257+
),
258+
preset_matchesAS (
259+
SELECT
260+
tvp.idAS template_version_preset_id,
261+
COALESCE(COUNT(tvpp.name),0)AS total_preset_params,
262+
COALESCE(COUNT(pp.name),0)AS matching_params
263+
FROM template_version_presets tvp
264+
LEFT JOIN template_version_preset_parameters tvppONtvpp.template_version_preset_id=tvp.id
265+
LEFT JOIN provided_params ppONpp.name=tvpp.nameANDpp.value=tvpp.value
266+
WHEREtvp.template_version_id= @template_version_id
267+
GROUP BYtvp.id
268+
)
269+
SELECTpm.template_version_preset_id
270+
FROM preset_matches pm
271+
WHEREpm.total_preset_params=pm.matching_params-- All preset parameters must match
272+
ORDER BYpm.total_preset_paramsDESC-- Return the preset with the most parameters
273+
LIMIT1;

‎coderd/prebuilds/parameters.go‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package prebuilds
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"errors"
7+
8+
"github.com/google/uuid"
9+
"golang.org/x/xerrors"
10+
11+
"github.com/coder/coder/v2/coderd/database"
12+
)
13+
14+
// FindMatchingPresetID finds a preset ID that matches the provided parameters.
15+
// It returns the preset ID if a match is found, or uuid.Nil if no match is found.
16+
// The function performs a bidirectional comparison to ensure all parameters match exactly.
17+
funcFindMatchingPresetID(
18+
ctx context.Context,
19+
store database.Store,
20+
templateVersionID uuid.UUID,
21+
parameterNames []string,
22+
parameterValues []string,
23+
) (uuid.UUID,error) {
24+
iflen(parameterNames)!=len(parameterValues) {
25+
returnuuid.Nil,xerrors.New("parameter names and values must have the same length")
26+
}
27+
28+
result,err:=store.FindMatchingPresetID(ctx, database.FindMatchingPresetIDParams{
29+
TemplateVersionID:templateVersionID,
30+
ParameterNames:parameterNames,
31+
ParameterValues:parameterValues,
32+
})
33+
iferr!=nil {
34+
// Handle the case where no matching preset is found (no rows returned)
35+
iferrors.Is(err,sql.ErrNoRows) {
36+
returnuuid.Nil,nil
37+
}
38+
returnuuid.Nil,xerrors.Errorf("find matching preset ID: %w",err)
39+
}
40+
41+
returnresult,nil
42+
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
package prebuilds_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/uuid"
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/coder/coder/v2/coderd/database"
11+
"github.com/coder/coder/v2/coderd/database/dbgen"
12+
"github.com/coder/coder/v2/coderd/database/dbtestutil"
13+
"github.com/coder/coder/v2/coderd/prebuilds"
14+
"github.com/coder/coder/v2/testutil"
15+
)
16+
17+
funcTestFindMatchingPresetID(t*testing.T) {
18+
t.Parallel()
19+
20+
presetIDs:= []uuid.UUID{
21+
uuid.New(),
22+
uuid.New(),
23+
}
24+
// Give each preset a meaningful name in alphabetical order
25+
presetNames:=map[uuid.UUID]string{
26+
presetIDs[0]:"development",
27+
presetIDs[1]:"production",
28+
}
29+
tests:= []struct {
30+
namestring
31+
parameterNames []string
32+
parameterValues []string
33+
presetParameters []database.TemplateVersionPresetParameter
34+
expectedPresetID uuid.UUID
35+
expectErrorbool
36+
errorContainsstring
37+
}{
38+
{
39+
name:"exact match",
40+
parameterNames: []string{"region","instance_type"},
41+
parameterValues: []string{"us-west-2","t3.medium"},
42+
presetParameters: []database.TemplateVersionPresetParameter{
43+
{TemplateVersionPresetID:presetIDs[0],Name:"region",Value:"us-west-2"},
44+
{TemplateVersionPresetID:presetIDs[0],Name:"instance_type",Value:"t3.medium"},
45+
// antagonist:
46+
{TemplateVersionPresetID:presetIDs[1],Name:"region",Value:"us-west-2"},
47+
{TemplateVersionPresetID:presetIDs[1],Name:"instance_type",Value:"t3.large"},
48+
},
49+
expectedPresetID:presetIDs[0],
50+
expectError:false,
51+
},
52+
{
53+
name:"no match - different values",
54+
parameterNames: []string{"region","instance_type"},
55+
parameterValues: []string{"us-east-1","t3.medium"},
56+
presetParameters: []database.TemplateVersionPresetParameter{
57+
{TemplateVersionPresetID:presetIDs[0],Name:"region",Value:"us-west-2"},
58+
{TemplateVersionPresetID:presetIDs[0],Name:"instance_type",Value:"t3.medium"},
59+
// antagonist:
60+
{TemplateVersionPresetID:presetIDs[1],Name:"region",Value:"us-west-2"},
61+
{TemplateVersionPresetID:presetIDs[1],Name:"instance_type",Value:"t3.large"},
62+
},
63+
expectedPresetID:uuid.Nil,
64+
expectError:false,
65+
},
66+
{
67+
name:"no match - fewer provided parameters",
68+
parameterNames: []string{"region"},
69+
parameterValues: []string{"us-west-2"},
70+
presetParameters: []database.TemplateVersionPresetParameter{
71+
{TemplateVersionPresetID:presetIDs[0],Name:"region",Value:"us-west-2"},
72+
{TemplateVersionPresetID:presetIDs[0],Name:"instance_type",Value:"t3.medium"},
73+
// antagonist:
74+
{TemplateVersionPresetID:presetIDs[1],Name:"region",Value:"us-west-2"},
75+
{TemplateVersionPresetID:presetIDs[1],Name:"instance_type",Value:"t3.large"},
76+
},
77+
expectedPresetID:uuid.Nil,
78+
expectError:false,
79+
},
80+
{
81+
name:"subset match - extra provided parameter",
82+
parameterNames: []string{"region","instance_type","extra_param"},
83+
parameterValues: []string{"us-west-2","t3.medium","extra_value"},
84+
presetParameters: []database.TemplateVersionPresetParameter{
85+
{TemplateVersionPresetID:presetIDs[0],Name:"region",Value:"us-west-2"},
86+
{TemplateVersionPresetID:presetIDs[0],Name:"instance_type",Value:"t3.medium"},
87+
// antagonist:
88+
{TemplateVersionPresetID:presetIDs[1],Name:"region",Value:"us-west-2"},
89+
{TemplateVersionPresetID:presetIDs[1],Name:"instance_type",Value:"t3.large"},
90+
},
91+
expectedPresetID:presetIDs[0],// Should match because all preset parameters are present
92+
expectError:false,
93+
},
94+
{
95+
name:"mismatched parameter names vs values",
96+
parameterNames: []string{"region","instance_type"},
97+
parameterValues: []string{"us-west-2"},
98+
presetParameters: []database.TemplateVersionPresetParameter{},
99+
expectedPresetID:uuid.Nil,
100+
expectError:true,
101+
errorContains:"parameter names and values must have the same length",
102+
},
103+
{
104+
name:"multiple presets - match first",
105+
parameterNames: []string{"region","instance_type"},
106+
parameterValues: []string{"us-west-2","t3.medium"},
107+
presetParameters: []database.TemplateVersionPresetParameter{
108+
{TemplateVersionPresetID:presetIDs[0],Name:"region",Value:"us-west-2"},
109+
{TemplateVersionPresetID:presetIDs[0],Name:"instance_type",Value:"t3.medium"},
110+
{TemplateVersionPresetID:presetIDs[1],Name:"region",Value:"us-east-1"},
111+
{TemplateVersionPresetID:presetIDs[1],Name:"instance_type",Value:"t3.large"},
112+
},
113+
expectedPresetID:presetIDs[0],
114+
expectError:false,
115+
},
116+
{
117+
name:"largest subset match",
118+
parameterNames: []string{"region","instance_type","storage_size"},
119+
parameterValues: []string{"us-west-2","t3.medium","100gb"},
120+
presetParameters: []database.TemplateVersionPresetParameter{
121+
{TemplateVersionPresetID:presetIDs[0],Name:"region",Value:"us-west-2"},
122+
{TemplateVersionPresetID:presetIDs[0],Name:"instance_type",Value:"t3.medium"},
123+
{TemplateVersionPresetID:presetIDs[1],Name:"region",Value:"us-west-2"},
124+
},
125+
expectedPresetID:presetIDs[0],// Should match the larger subset (2 params vs 1 param)
126+
expectError:false,
127+
},
128+
}
129+
130+
for_,tt:=rangetests {
131+
tt:=tt
132+
t.Run(tt.name,func(t*testing.T) {
133+
t.Parallel()
134+
135+
ctx:=testutil.Context(t,testutil.WaitShort)
136+
db,_:=dbtestutil.NewDB(t)
137+
org:=dbgen.Organization(t,db, database.Organization{})
138+
user:=dbgen.User(t,db, database.User{})
139+
templateVersion:=dbgen.TemplateVersion(t,db, database.TemplateVersion{
140+
OrganizationID:org.ID,
141+
CreatedBy:user.ID,
142+
JobID:uuid.New(),
143+
})
144+
145+
// Group parameters by preset ID and create presets
146+
presetMap:=make(map[uuid.UUID][]database.TemplateVersionPresetParameter)
147+
for_,param:=rangett.presetParameters {
148+
presetMap[param.TemplateVersionPresetID]=append(presetMap[param.TemplateVersionPresetID],param)
149+
}
150+
151+
// Create presets and insert their parameters
152+
forpresetID,params:=rangepresetMap {
153+
// Create the preset
154+
_,err:=db.InsertPreset(ctx, database.InsertPresetParams{
155+
ID:presetID,
156+
TemplateVersionID:templateVersion.ID,
157+
Name:presetNames[presetID],
158+
CreatedAt:dbtestutil.NowInDefaultTimezone(),
159+
})
160+
require.NoError(t,err)
161+
162+
// Insert parameters for this preset
163+
names:=make([]string,len(params))
164+
values:=make([]string,len(params))
165+
fori,param:=rangeparams {
166+
names[i]=param.Name
167+
values[i]=param.Value
168+
}
169+
170+
_,err=db.InsertPresetParameters(ctx, database.InsertPresetParametersParams{
171+
TemplateVersionPresetID:presetID,
172+
Names:names,
173+
Values:values,
174+
})
175+
require.NoError(t,err)
176+
}
177+
178+
result,err:=prebuilds.FindMatchingPresetID(
179+
ctx,
180+
db,
181+
templateVersion.ID,
182+
tt.parameterNames,
183+
tt.parameterValues,
184+
)
185+
186+
// Assert results
187+
iftt.expectError {
188+
require.Error(t,err)
189+
iftt.errorContains!="" {
190+
assert.Contains(t,err.Error(),tt.errorContains)
191+
}
192+
}else {
193+
require.NoError(t,err)
194+
assert.Equal(t,tt.expectedPresetID,result)
195+
}
196+
})
197+
}
198+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp