-
Notifications
You must be signed in to change notification settings - Fork 3
feat: initial implementation of coder-doctor #3
Conversation
This pull request has been linked to Clubhouse Story #15961: Initial implementation of coder-doctor framework. |
Such a massive fan of this! We can use this package to validate clusters are properly configured when being added too. 🥳🥳🥳 |
}, | ||
} | ||
|
||
for _, test := range tests { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should autogenerate some tests (with dummy data for version fields we don't care about) for all of our supported versions
5fb3b2b
to
f2f9988
Compare
|
||
var _ = fmt.Stringer(StatePassed) | ||
|
||
type CheckState int |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we make these integers rather than strings?
That way we could eliminate the string function, and set the values to the const names.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There wasn't a particular reason, no! I thought that integers were just the common way to do enums like this in Go.
A nice benefit of this is that the filtering can be done with bitwise operations (to determine whether to log each level), but of course we could do that with a set of bools or something too: https://github.com/cdr/coder-doctor/blob/31cb1c565fc42be9b40d9c68e634625287086b0b/internal/filterwriter/filter.go#L42-L60
I suppose another benefit is that comparisons should be faster with integers, because then it's just a numeric equality instead of string comparison
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neato. Appreciate the context, and I'd agree with you here!
@johnstcn I wanted to get this initial version merged, can you take another look? I think you'd be the perfect reviewer for this since you've been working with the CLI more lately. It's not complete and just checks the version for now, but it's going to be harder to iterate on this with the existing PR due to the size. If you want to test locally, you should be able to clone the branch and run:
This will use your current kubectl context (or you can also specify flags like --context) |
emoji, err := state.Emoji() | ||
assert.Success(t, "state.Emoji() error non-nil", err) | ||
assert.True(t, "state.Emoji() is non-empty", len(emoji) > 0) | ||
_ = state.MustEmoji() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️ this
|
||
type CoderVersionRequirement struct { | ||
CoderVersion *semver.Version | ||
KubernetesVersionMin *semver.Version |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we can probably use a semver.Constraint
instead of specifying new versions, but this works for now.
https://pkg.go.dev/github.com/Masterminds/semver#hdr-Checking_Version_Constraints
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can, but that API is a little more annoying to use because there's no Must
variant. I suppose we could specify all of these as strings and parse at runtime?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're probably better off doing as much as possible at compile-time!
|
||
// TODO: this is pretty arbitrary, use a defined verbosity similar to | ||
// kubectl | ||
if verbosity > 5 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ha, I usually set --verbosity=99
or something if I see something like that and want to be extra-verbose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kubectl has a really nicely-defined list, with criteria for what goes where -- I think we should adopt similar definitions, because otherwise (as a developer), it's difficult to know what level to log things, and it makes the level kinda useless for users: https://kubernetes.io/docs/reference/kubectl/_print/#kubectl-output-verbosity-and-debugging
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice one!
./main check kubernetes --verbosity 9999
2021-08-16 15:23:50.681 [DEBUG] <version.go:67> selected coder version {"requested": "1.21.0", "selected": "1.21.0"}
PASS Coder 1.21.0 supports Kubernetes 1.19.0 to 1.22.0 (server version 1.20.8-gke.900)
internal/checks/kube/kubernetes.go
Outdated
func (k *KubernetesChecker) Run(ctx context.Context) error { | ||
err := k.writer.WriteResult(k.CheckVersion(ctx)) | ||
if err != nil { | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add more xerrors.Errorf(...
about the place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excellent point, done!
|
||
kubernetesVersion, err := semver.NewVersion(versionInfo.GitVersion) | ||
if err != nil { | ||
return api.ErrorResult(checkName, "failed to parse server version", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we return a different message here than line 63 e.g. failed to parse git version info from server
? Exact wording chef's choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
excellent catch! changed the error on line 63 to read: failed to unmarshal version info
instead, to clarify what it's actually doing
|
||
overrides.CurrentContext, err = cmd.Flags().GetString(clientcmd.FlagContext) | ||
if err != nil { | ||
return nil, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
xerrors.Errorf(...
and below
var expected string | ||
switch mode { | ||
case humanwriter.OutputModeEmoji: | ||
expected = "👍 human writer check test\n" + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the pass and fail emoji are easy to confuse at a glance, suggest ✅ and ❌ for maximum distinguishability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, I don't feel strongly about it and suggest we try it as it is for a bit to see what we think -- we can always change it later
|
||
// This uses the RESTClient rather than Discovery().ServerVersion() | ||
// because the latter does not accept a context. | ||
body, err := k.client.Discovery().RESTClient().Get().AbsPath("/version").Do(ctx).Raw() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on second thought, I think splitting this into a KubernetesVersionChecker struct might be useful, it could use a DiscoveryClient interface or RESTClient as its arg instead of a kubernetes.Interface
-- that would make it easier to unit test https://pkg.go.dev/k8s.io/client-go@v0.22.0/kubernetes/typed/discovery/v1#DiscoveryV1Interface
but I think that's something for later
No description provided.