-
Notifications
You must be signed in to change notification settings - Fork 102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor init code into setup package #1161
Conversation
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.
I must say I don't understand why we introduced a new package named 'setup'. Could you share the motivation? I am kind of against it - in KUDO world I feel like this process is called init and we should stick to using this name even in the internal package structure so I am kind of leaning toward the manifest code being in the init package.
Also could you help me figure out what are the interesting pieces to review here? It's 700 lines and as I went over it most is just moved code and it's hard to find the pieces that are actually worth reviewing (and I think there's probably just few for now). Could you maybe put comments to them? So far I assume it's the cleaned up handling in the /cmd/init.go
. Is there more?
var mans []string | ||
|
||
crd, err := cmdInit.CRDs().AsYaml() | ||
manifests, err := setup.AsYamlManifests(opts, initCmd.crdOnly) |
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 👍 much cleaner
So, the motivation for a new package in general is that the whole init process will become bigger with migrations, upgrading, etc. I don't think it should be in the As for the name I'll add some comments in the code and in the review to make it easier to find the details |
Ah. There it is. I just renamed
|
hmm but we already had package init, so the name cannot be a problem? 🤔 So what would you think of having package init with sub-package migrations when migrations come in... What do you think about something like this:
|
Well, you can have a package
And at least IntelliJ doesn't do that automatically. (And doesn't complain about init. Only the go compiler does :-/) About the sub packages: That was what I initially started with. Then it got kinda messy, because there are the options, which are passed into the init-code. As it's used from outside, it would be nice to have it I've read a bit about packages in go, and decided to not use sub-packages for the moment, as that seems to be the go-way. tbh, I'd prefer to having them, but that seems not to be that easy. |
pkg/kudoctl/setup/prereqs.go
Outdated
type k8sResource interface { | ||
Install(client *kube.Client) error | ||
Validate(client *kube.Client) error | ||
AsRuntimeObj() []runtime.Object | ||
} |
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 is one of the nicer things of the refactoring: There's an abstraction for one or more manifests as a prerequisite, currently implemented in each of the prereq_*.go
files. We can extend that with methods for migration, deletion, etc.
pkg/kudoctl/setup/setup.go
Outdated
@@ -0,0 +1,115 @@ | |||
package setup |
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 is now the main entry point for initialization of the cluster - At some point this should also provide functionality to validate the installation, upgrade the KUDO installation, etc.
Can you share some background to this - like some articles you read? I am just curious. I have not read much about packages in go in particular but to me this is just a general problem of encapsulation so I want to have packages that encapsulate code that somehow relates and that is changed in a similar situations, so from that point of view since migrations are very init specific for us right now, I would not mind having them as a sub-package. |
Fixed integration test that expected the custom SA and RB manifests in yaml output #1165
This is the article I read: Regarding encapsulation: I feel that go isn't really big on encapsulation. It mostly seems to be organized by conventions instead of hard rules or by means of language features. As i'm not sure how exactly we're going to implement the migrations/upgrade process, I think it's fine as it is now, but if we end up with custom migration code, I don't mind having that in a sub package. |
As discussed offline, k8s and KUDO both adopted the types-pattern for dealing with circular dependency hell.
where |
I now made a refactoring attempt that works like this:
which is similar to yours, that might work as well. Not committed and pushed yet, as i'm not totally sold, but it does look a bit more organized. |
# Conflicts: # pkg/kudoctl/cmd/init.go # pkg/kudoctl/cmd/init/prereqs.go
I like it! |
Nice! Please drop the |
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.
Loving the new structure ❤️
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.
I left a few comments so PTAL. But overall the new structure is a win!
├── crd
│ └── crds.go
├── manager
│ └── manager.go
├── prereq
│ ├── namespace.go
│ ├── prereqs.go
│ ├── serviceaccount.go
│ └── webhook.go
├── setup
│ ├── setup.go
│ └── wait.go
└── types.go```
❤️
@@ -337,7 +339,7 @@ func TestNoErrorOnReInit(t *testing.T) { | |||
assert.IsType(t, &meta.NoKindMatchError{}, testClient.Create(context.TODO(), instance)) | |||
|
|||
// Install all of the CRDs. | |||
crds := cmdinit.CRDs().AsArray() | |||
crds := crd.NewInitializer().AsArray() |
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.
I like how package prefix already tells the reader what is being initialized here! 👍
ns *v1.Namespace | ||
} | ||
|
||
func newNamespaceSetup(options kudoinit.Options) KudoNamespace { |
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: simply newNamespace
or newKudoNamespace
. constructor methods are by convention named new + objectName
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.
Good point, fixed that. I also made the KudoNamespace
, KudoServiceAccount
and KudoWebhook
private, as they're only used internally in the prereq
package
pkg/kudoctl/kudoinit/types.go
Outdated
AsArray() []runtime.Object | ||
} | ||
|
||
// Options is the configurable options to init |
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.
I'd prefer types.go
being about types only (no methods). Can we put Options
and all methods in options.go
? We can leave it in /kudoinit/options.go
for now.
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.
Yeah, I like that. Done
} | ||
} | ||
|
||
func GenerateLabels(labels map[string]string) map[string]string { |
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 would be a kudo_labels.go
but I feel that @alenkacz would hate me for suggesting a new file for a two-liner :D
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.
Yeah, i'm not too happy with this either. I thought about putting it in the Options
object, but... it's not an option. I'll leave it here for now, maybe we'll find a good place later on when the init process grows.
// installInstanceValidatingWebhook applies kubernetes resources related to the webhook to the cluster | ||
func installInstanceValidatingWebhook(client kubernetes.Interface, dynamicClient dynamic.Interface, ns string) error { | ||
if err := installUnstructured(dynamicClient, certificate(ns)); err != nil { | ||
// Ensure IF is implemented |
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.
// Ensure IF is implemented | |
// Ensure kudoinit.InitStep interface is implemented |
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.
Fixed
What this PR does / why we need it:
Clean up the init code that sets up the cluster, installs prerequisites and CRDs and deploys the manager.
--dry-run --output yaml
Fixes #1160