diff --git a/tailnet/service.go b/tailnet/service.go new file mode 100644 index 0000000000..92140aa3f5 --- /dev/null +++ b/tailnet/service.go @@ -0,0 +1,47 @@ +package tailnet + +import ( + "strconv" + "strings" + + "golang.org/x/xerrors" +) + +const ( + CurrentMajor = 2 + CurrentMinor = 0 +) + +var SupportedMajors = []int{2, 1} + +func ValidateVersion(version string) error { + parts := strings.Split(version, ".") + if len(parts) != 2 { + return xerrors.Errorf("invalid version string: %s", version) + } + major, err := strconv.Atoi(parts[0]) + if err != nil { + return xerrors.Errorf("invalid major version: %s", version) + } + minor, err := strconv.Atoi(parts[1]) + if err != nil { + return xerrors.Errorf("invalid minor version: %s", version) + } + if major > CurrentMajor { + return xerrors.Errorf("server is at version %d.%d, behind requested version %s", + CurrentMajor, CurrentMinor, version) + } + if major == CurrentMajor { + if minor > CurrentMinor { + return xerrors.Errorf("server is at version %d.%d, behind requested version %s", + CurrentMajor, CurrentMinor, version) + } + return nil + } + for _, mjr := range SupportedMajors { + if major == mjr { + return nil + } + } + return xerrors.Errorf("version %s is no longer supported", version) +} diff --git a/tailnet/service_test.go b/tailnet/service_test.go new file mode 100644 index 0000000000..ffb0442aea --- /dev/null +++ b/tailnet/service_test.go @@ -0,0 +1,74 @@ +package tailnet_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/coder/coder/v2/tailnet" +) + +func TestValidateVersion(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + name string + version string + supported bool + }{ + { + name: "Current", + version: fmt.Sprintf("%d.%d", tailnet.CurrentMajor, tailnet.CurrentMinor), + supported: true, + }, + { + name: "TooNewMinor", + version: fmt.Sprintf("%d.%d", tailnet.CurrentMajor, tailnet.CurrentMinor+1), + }, + { + name: "TooNewMajor", + version: fmt.Sprintf("%d.%d", tailnet.CurrentMajor+1, tailnet.CurrentMinor), + }, + { + name: "1.0", + version: "1.0", + supported: true, + }, + { + name: "2.0", + version: "2.0", + supported: true, + }, + { + name: "Malformed0", + version: "cats", + }, + { + name: "Malformed1", + version: "cats.dogs", + }, + { + name: "Malformed2", + version: "1.0.1", + }, + { + name: "Malformed3", + version: "11", + }, + { + name: "TooOld", + version: "0.8", + }, + } { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + err := tailnet.ValidateVersion(tc.version) + if tc.supported { + require.NoError(t, err) + } else { + require.Error(t, err) + } + }) + } +}