-
Notifications
You must be signed in to change notification settings - Fork 706
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
Add basic Helm 3 support (with ListReleases only) #1359
Add basic Helm 3 support (with ListReleases only) #1359
Conversation
This commit doesn't import said package, but here is an example: import ( "fmt" "helm.sh/helm/v3/pkg/action" ) func Hello() { fmt.Printf("%v\n", new(action.Configuration)) } Most of the changes in this commit are actually made/suggested by @andresmgot.
Tiller Proxy is still used by default. Set useHelm3 to true in values.yaml to use Kubeops instead.
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.
LGTM, and I'll take a look at setting up tests so you can continue with the other ones.
Hmm, did you see the CI error? FAIL use-cases/default-deployment.js (71.032s)
. Not sure if it was an intermittent error, or whether that is reproduced locally? (I mean, nothing should be effected since CI is running without the useHelm3
flag, but haven't dug).
serviceAccountName: {{ template "kubeapps.kubeops.fullname" . }} | ||
# Increase termination timeout to let remaining operations to finish before killing the pods | ||
# This is because new releases/upgrades/deletions are synchronous operations | ||
terminationGracePeriodSeconds: 300 |
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 expected that this would only be required if the API equivalent of the --wait
flag was used? Doesn't a new release return as soon as the yaml resources have been created?
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 don't know tbh; this file is basically just tiller-proxy-deployment.yaml
adapted for Kubeops.
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.
background here: even if you don't use the --wait
flag, the installation/upgrade/deletion of a chart may not return instantaneously if the chart has a hook. For example, in the case of Kubeapps, it's not until the initialRepos
are populated (pre-install hook) when the rest of the chart is installed.
- name: POD_NAMESPACE | ||
valueFrom: | ||
fieldRef: | ||
fieldPath: metadata.namespace |
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.
Not needed straight away, but keep in mind we'll want to include liveness/readiness probes too (I only just hooked up the ones for tiller-proxy in #1348 which were never added).
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 see. Shouldn't be any problem.
@@ -71,7 +70,7 @@ func setConfigDefaults(config *rest.Config) error { | |||
gv := v1alpha1.SchemeGroupVersion | |||
config.GroupVersion = &gv | |||
config.APIPath = "/apis" | |||
config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} | |||
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() |
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 assume this and the related change below are just from package updates? Or otherwise, why the change?
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.
Most of the modifications in that commit were suggested by @andresmgot so that we could import helm.sh/helm/v3
at all.
Namespace: r.Namespace, | ||
Status: r.Info.Status.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.
Great, I'll have a look at testing this and the handler tomorrow. Thanks!
Yep, I saw it. No idea why, really. This line seems to be the one failing: await expect(page).toMatch("Ready", { timeout: 60000 }); |
Hrm, testing this locally, I see the following when I try a default deploy of aerospike (well, anything): which would explain the failing test. I'll try to find if one of the updates has altered the token authentication which is done in tiller-proxy so you can move on. I've done some sample tests you can merge for |
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.
Thanks for the PR @SimonAlling! It mostly looks good to me, I only have a few comments. I am checking the issue that the CI raised, I suspect it's caused by the changes in the go.mod
but will need to verify.
serviceAccountName: {{ template "kubeapps.kubeops.fullname" . }} | ||
# Increase termination timeout to let remaining operations to finish before killing the pods | ||
# This is because new releases/upgrades/deletions are synchronous operations | ||
terminationGracePeriodSeconds: 300 |
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.
background here: even if you don't use the --wait
flag, the installation/upgrade/deletion of a chart may not return instantaneously if the chart has a hook. For example, in the case of Kubeapps, it's not until the initialRepos
are populated (pre-install hook) when the rest of the chart is installed.
cmd/kubeops/main.go
Outdated
// Will panic below if an invalid driver type is provided. | ||
driverType := defaultHelmDriver | ||
if helmDriverArg != "" { | ||
driverType = agent.ParseDriverType(helmDriverArg) | ||
} else { | ||
// CLI argument was not provided; check environment variable. | ||
helmDriverEnv := os.Getenv(driverEnvVar) | ||
if helmDriverEnv != "" { | ||
driverType = agent.ParseDriverType(helmDriverEnv) | ||
} | ||
} |
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.
it's okay but why supporting the flag and the env var? In any case, I would rather use just the flag with a default value.
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 did that because Helm did. I'll be happy to remove the env var if you prefer just the flag.
actionConfig.RESTClientGetter = nil // TODO replace nil with meaningful value | ||
actionConfig.KubeClient = kube.New(nil) // TODO replace nil with meaningful value |
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.
are these lines really necessary?
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 guess it depends on your definition of "necessary". We probably thought it would be nice to be explicit. What would you recommend: keep or remove?
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.
it's okay to leave it, I guess what I don't understand is the TODO
note, why should it have a meaningful value? What's a meaningful value in this context?
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 don't know; I still don't fully grasp how everything fits together in this fairly complex system. I thought nil
was obviously not meaningful and would need to be replaced sooner or later.
// No (real) enums/ADTs in Go, so no static guarantee against this case. | ||
panic("Invalid Helm driver type: " + driverType) |
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.
it's better to return an error than panicking, that way the caller can act in consequence.
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.
In this specific case, I'm actually not sure about that. I wanted to have the first argument to agent.createStorage
be of a sum type, so that I'd only need to handle exactly the cases represented by that sum type. There seems to be no sum types in Go, so said first argument instead has the quasi sum type DriverType
. This at least means that values like os.Getenv("LOL"))
don't typecheck:
cannot use os.Getenv("LOL") (type string) as type agent.DriverType in argument to handler.WithAgentConfig
However, values like "hello"
apparently count as members of DriverType
, but I found no way around that.
I think returning an error in createStorage
would introduce a lot of (IMO) unnecessary complexity in agent.NewActionConfig
and handler.WithAgentConfig
. I also think a programmer will understand that they're not supposed to pass "hello"
, but an actual DriverType
(e.g. agent.Secret
).
At some point, you want to be able to say "I have a value of type T – I know it has been validated because it is a T." Parse, don't validate. Go doesn't seem to help us more than I've already made it do.
I'm much more inclined to make agent.ParseDriverType
return an error instead of panicking, because, unlike createStorage
, it promises that it can handle any string
. Its current deceitfulness stems from my interpretation of @absoludity's suggestion that Kubeops should refuse to start if an invalid driver type has been specified. I'll be more than happy to return an error instead.
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.
If I understand this correctly, you mean that driverType
was validated before so this won't never panic, right? (because the driver was parsed before). If that's the case then it's fine, I just found it weird for a function in a library to panic.
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, it is weird. But Go doesn't seem to let me express a good old sum type, so this was the best solution I could come up with. It is correct that createStorage
should never panic, because driverType
should really be a DriverType
. The only way I know to violate this assumption is to pass a string literal as driverType
.
@@ -320,7 +320,7 @@ func (c *Chart) InitNetClient(details *Details) (HTTPClient, error) { | |||
|
|||
defaultHeaders := http.Header{"User-Agent": []string{c.userAgent}} | |||
if auth.Header != nil { | |||
secret, err := c.kubeClient.Core().Secrets(namespace).Get(auth.Header.SecretKeyRef.Name, metav1.GetOptions{}) | |||
secret, err := c.kubeClient.CoreV1().Secrets(namespace).Get(auth.Header.SecretKeyRef.Name, metav1.GetOptions{}) |
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.
why this change?
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 don't know. I think you suggested it. (Do note that it's part of 1e1a3ba.)
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 guess that was me trying things, you don't need this change
I just tried deploying Aerospike as well, and I wasn't able to reproduce the issue. I trust you and CircleCI more than myself, though. Having submitted this comment, I tried deploying Airflow (from
But no other app I've tried has thrown any error. |
I think it would be interesting to run 1e1a3ba through CI, because it's the only commit on this branch that I'd reasonably expect to affect any existing functionality. |
I was able to also reproduce the issue (I just built the https://github.com/kubeapps/kubeapps/blob/master/pkg/auth/auth.go#L77 The response returned is empty so both allowed and denied are
If you are not able to reproduce the issue, it may be related to an issue with |
I am also able to reproduce it with minikube so I guess it's a different thing (btw, using Kubernetes 1.16) |
Finally found the issue (this one was a tough one). The problem is that the --- a/pkg/auth/auth.go
+++ b/pkg/auth/auth.go
@@ -105,6 +105,7 @@ func NewAuth(token string) (*UserAuth, error) {
}
// Overwrite default token
config.BearerToken = token
+ config.BearerTokenFile = ""
kubeClient, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err here: https://github.com/kubeapps/kubeapps/blob/master/pkg/auth/auth.go#L107 |
As suggested by @andresmgot: vmware-tanzu#1359 (comment)
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.
It's okay for me to have a starting point. Leaving for @absoludity to do a final review. Thanks!
Thank you so much for helping me out with the 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.
Excellent - great work digging on the token issue Andres. Thanks Simon - great to start getting this in master!
Related discussion: vmware-tanzu#1359 (comment)
Description of the change
It implements
ListReleases
andListAllReleases
using the Helm 3 API.Note:
useHelm3
must be set totrue
invalues.yaml
for the changes introduced here to have any effect.Benefits
We should get one step closer to Helm 3 support.
Possible drawbacks
There are no tests. (Hello, @absoludity!)
Applicable issues
This PR emerged from the discussion in #1309.
Additional information
We went with the name Kubeops this time (instead of Helmer).