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

Commit4d2fe26

Browse files
authored
chore(coderd): extract api version validation to util package (#11407)
1 parent58873fa commit4d2fe26

File tree

5 files changed

+178
-110
lines changed

5 files changed

+178
-110
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package apiversion
2+
3+
import (
4+
"strconv"
5+
"strings"
6+
7+
"golang.org/x/xerrors"
8+
)
9+
10+
// New returns an *APIVersion with the given major.minor and
11+
// additional supported major versions.
12+
funcNew(maj,minint)*APIVersion {
13+
v:=&APIVersion{
14+
supportedMajor:maj,
15+
supportedMinor:min,
16+
additionalMajors:make([]int,0),
17+
}
18+
returnv
19+
}
20+
21+
typeAPIVersionstruct {
22+
supportedMajorint
23+
supportedMinorint
24+
additionalMajors []int
25+
}
26+
27+
func (v*APIVersion)WithBackwardCompat(majs...int)*APIVersion {
28+
v.additionalMajors=append(v.additionalMajors,majs[:]...)
29+
returnv
30+
}
31+
32+
// Validate validates the given version against the given constraints:
33+
// A given major.minor version is valid iff:
34+
// 1. The requested major version is contained within v.supportedMajors
35+
// 2. If the requested major version is the 'current major', then
36+
// the requested minor version must be less than or equal to the supported
37+
// minor version.
38+
//
39+
// For example, given majors {1, 2} and minor 2, then:
40+
// - 0.x is not supported,
41+
// - 1.x is supported,
42+
// - 2.0, 2.1, and 2.2 are supported,
43+
// - 2.3+ is not supported.
44+
func (v*APIVersion)Validate(versionstring)error {
45+
major,minor,err:=Parse(version)
46+
iferr!=nil {
47+
returnerr
48+
}
49+
ifmajor>v.supportedMajor {
50+
returnxerrors.Errorf("server is at version %d.%d, behind requested major version %s",
51+
v.supportedMajor,v.supportedMinor,version)
52+
}
53+
ifmajor==v.supportedMajor {
54+
ifminor>v.supportedMinor {
55+
returnxerrors.Errorf("server is at version %d.%d, behind requested minor version %s",
56+
v.supportedMajor,v.supportedMinor,version)
57+
}
58+
returnnil
59+
}
60+
for_,mjr:=rangev.additionalMajors {
61+
ifmajor==mjr {
62+
returnnil
63+
}
64+
}
65+
returnxerrors.Errorf("version %s is no longer supported",version)
66+
}
67+
68+
// Parse parses a valid major.minor version string into (major, minor).
69+
// Both major and minor must be valid integers separated by a period '.'.
70+
funcParse(versionstring) (majorint,minorint,errerror) {
71+
parts:=strings.Split(version,".")
72+
iflen(parts)!=2 {
73+
return0,0,xerrors.Errorf("invalid version string: %s",version)
74+
}
75+
major,err=strconv.Atoi(parts[0])
76+
iferr!=nil {
77+
return0,0,xerrors.Errorf("invalid major version: %s",version)
78+
}
79+
minor,err=strconv.Atoi(parts[1])
80+
iferr!=nil {
81+
return0,0,xerrors.Errorf("invalid minor version: %s",version)
82+
}
83+
returnmajor,minor,nil
84+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package apiversion_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
8+
"github.com/coder/coder/v2/coderd/util/apiversion"
9+
)
10+
11+
funcTestAPIVersionValidate(t*testing.T) {
12+
t.Parallel()
13+
14+
// Given
15+
v:=apiversion.New(2,1).WithBackwardCompat(1)
16+
17+
for_,tc:=range []struct {
18+
namestring
19+
versionstring
20+
expectedErrorstring
21+
}{
22+
{
23+
name:"OK",
24+
version:"2.1",
25+
},
26+
{
27+
name:"MinorOK",
28+
version:"2.0",
29+
},
30+
{
31+
name:"MajorOK",
32+
version:"1.0",
33+
},
34+
{
35+
name:"TooNewMinor",
36+
version:"2.2",
37+
expectedError:"behind requested minor version",
38+
},
39+
{
40+
name:"TooNewMajor",
41+
version:"3.1",
42+
expectedError:"behind requested major version",
43+
},
44+
{
45+
name:"Malformed0",
46+
version:"cats",
47+
expectedError:"invalid version string",
48+
},
49+
{
50+
name:"Malformed1",
51+
version:"cats.dogs",
52+
expectedError:"invalid major version",
53+
},
54+
{
55+
name:"Malformed2",
56+
version:"1.dogs",
57+
expectedError:"invalid minor version",
58+
},
59+
{
60+
name:"Malformed3",
61+
version:"1.0.1",
62+
expectedError:"invalid version string",
63+
},
64+
{
65+
name:"Malformed4",
66+
version:"11",
67+
expectedError:"invalid version string",
68+
},
69+
{
70+
name:"TooOld",
71+
version:"0.8",
72+
expectedError:"no longer supported",
73+
},
74+
} {
75+
tc:=tc
76+
t.Run(tc.name,func(t*testing.T) {
77+
t.Parallel()
78+
79+
// When
80+
err:=v.Validate(tc.version)
81+
82+
// Then
83+
iftc.expectedError=="" {
84+
require.NoError(t,err)
85+
}else {
86+
require.ErrorContains(t,err,tc.expectedError)
87+
}
88+
})
89+
}
90+
}

‎coderd/workspaceagents.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,7 @@ func (api *API) workspaceAgentClientCoordinate(rw http.ResponseWriter, r *http.R
11801180
ifqv!="" {
11811181
version=qv
11821182
}
1183-
iferr:=tailnet.ValidateVersion(version);err!=nil {
1183+
iferr:=tailnet.CurrentVersion.Validate(version);err!=nil {
11841184
httpapi.Write(ctx,rw,http.StatusBadRequest, codersdk.Response{
11851185
Message:"Unknown or unsupported API version",
11861186
Validations: []codersdk.ValidationError{

‎tailnet/service.go‎

Lines changed: 3 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ import (
44
"context"
55
"io"
66
"net"
7-
"strconv"
8-
"strings"
97
"sync/atomic"
108
"time"
119

@@ -16,6 +14,7 @@ import (
1614
"tailscale.com/tailcfg"
1715

1816
"cdr.dev/slog"
17+
"github.com/coder/coder/v2/coderd/util/apiversion"
1918
"github.com/coder/coder/v2/tailnet/proto"
2019

2120
"golang.org/x/xerrors"
@@ -26,47 +25,7 @@ const (
2625
CurrentMinor=0
2726
)
2827

29-
varSupportedMajors= []int{2,1}
30-
31-
funcValidateVersion(versionstring)error {
32-
major,minor,err:=parseVersion(version)
33-
iferr!=nil {
34-
returnerr
35-
}
36-
ifmajor>CurrentMajor {
37-
returnxerrors.Errorf("server is at version %d.%d, behind requested version %s",
38-
CurrentMajor,CurrentMinor,version)
39-
}
40-
ifmajor==CurrentMajor {
41-
ifminor>CurrentMinor {
42-
returnxerrors.Errorf("server is at version %d.%d, behind requested version %s",
43-
CurrentMajor,CurrentMinor,version)
44-
}
45-
returnnil
46-
}
47-
for_,mjr:=rangeSupportedMajors {
48-
ifmajor==mjr {
49-
returnnil
50-
}
51-
}
52-
returnxerrors.Errorf("version %s is no longer supported",version)
53-
}
54-
55-
funcparseVersion(versionstring) (majorint,minorint,errerror) {
56-
parts:=strings.Split(version,".")
57-
iflen(parts)!=2 {
58-
return0,0,xerrors.Errorf("invalid version string: %s",version)
59-
}
60-
major,err=strconv.Atoi(parts[0])
61-
iferr!=nil {
62-
return0,0,xerrors.Errorf("invalid major version: %s",version)
63-
}
64-
minor,err=strconv.Atoi(parts[1])
65-
iferr!=nil {
66-
return0,0,xerrors.Errorf("invalid minor version: %s",version)
67-
}
68-
returnmajor,minor,nil
69-
}
28+
varCurrentVersion=apiversion.New(CurrentMajor,CurrentMinor).WithBackwardCompat(1)
7029

7130
typestreamIDContextKeystruct{}
7231

@@ -127,7 +86,7 @@ func NewClientService(
12786
}
12887

12988
func (s*ClientService)ServeClient(ctx context.Context,versionstring,conn net.Conn,id uuid.UUID,agent uuid.UUID)error {
130-
major,_,err:=parseVersion(version)
89+
major,_,err:=apiversion.Parse(version)
13190
iferr!=nil {
13291
s.logger.Warn(ctx,"serve client called with unparsable version",slog.Error(err))
13392
returnerr

‎tailnet/service_test.go‎

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package tailnet_test
22

33
import (
44
"context"
5-
"fmt"
65
"io"
76
"net"
87
"net/http"
@@ -25,70 +24,6 @@ import (
2524
"github.com/coder/coder/v2/tailnet"
2625
)
2726

28-
funcTestValidateVersion(t*testing.T) {
29-
t.Parallel()
30-
for_,tc:=range []struct {
31-
namestring
32-
versionstring
33-
supportedbool
34-
}{
35-
{
36-
name:"Current",
37-
version:fmt.Sprintf("%d.%d",tailnet.CurrentMajor,tailnet.CurrentMinor),
38-
supported:true,
39-
},
40-
{
41-
name:"TooNewMinor",
42-
version:fmt.Sprintf("%d.%d",tailnet.CurrentMajor,tailnet.CurrentMinor+1),
43-
},
44-
{
45-
name:"TooNewMajor",
46-
version:fmt.Sprintf("%d.%d",tailnet.CurrentMajor+1,tailnet.CurrentMinor),
47-
},
48-
{
49-
name:"1.0",
50-
version:"1.0",
51-
supported:true,
52-
},
53-
{
54-
name:"2.0",
55-
version:"2.0",
56-
supported:true,
57-
},
58-
{
59-
name:"Malformed0",
60-
version:"cats",
61-
},
62-
{
63-
name:"Malformed1",
64-
version:"cats.dogs",
65-
},
66-
{
67-
name:"Malformed2",
68-
version:"1.0.1",
69-
},
70-
{
71-
name:"Malformed3",
72-
version:"11",
73-
},
74-
{
75-
name:"TooOld",
76-
version:"0.8",
77-
},
78-
} {
79-
tc:=tc
80-
t.Run(tc.name,func(t*testing.T) {
81-
t.Parallel()
82-
err:=tailnet.ValidateVersion(tc.version)
83-
iftc.supported {
84-
require.NoError(t,err)
85-
}else {
86-
require.Error(t,err)
87-
}
88-
})
89-
}
90-
}
91-
9227
funcTestClientService_ServeClient_V2(t*testing.T) {
9328
t.Parallel()
9429
fCoord:=newFakeCoordinator()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp