-
Notifications
You must be signed in to change notification settings - Fork 230
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
Initial proposal of the new Helmops controller. #3092
base: main
Are you sure you want to change the base?
Conversation
b8eac37
to
5324f8f
Compare
It adds a new custom resource `HelmApp` (resource name open to debate) that describes a helm chart to be deployed. The resource contains all the fealds from the classic `fleet.yaml` file plus a few new from the `GitRepo` resource. `HelmApp` yaml example: ```yaml apiVersion: fleet.cattle.io/v1alpha1 kind: HelmApp metadata: name: sample1 namespace: fleet-local spec: helm: releaseName: testhelm repo: https://charts.bitnami.com/bitnami chart: postgresql version: 16.2.1 insecureSkipTLSVerify: true ``` The implementation tries to share as much as possible from a `Bundle` spec inside the new resource, because it helps to "transform" the `HelmApp` into a deployment (no coversion is needed for most of the spec). The new controller was also implemented splitting the functionality into 2 controllers (similar to what we did for the `GitRepo` controller). This allows us to reuse most of the status handling code, as display fields in the status of the new resource are as similar as possible to have consistent user experience and to integrate with the UI in the same way the `GitRepo` does. When a new `HelmApp` resource is applied it is transformed into a single `Bundle`, adding some extra fields to let the `Bundle` reconciler know that this is not a regular `Bundle` coming from a `GitRepo`. Similar as we did for OCI storage, the `Bundle` created from a `HelmApp` does not contain resources. The helm chart to be deployed is downloaded by the agent. Code for downloading the helm chart is reused from gitops, so the same formats are supported. Insecure TLS skipping was added the the ChartURL and LoadDirectory functions in order to support this for gitops and helmops. If we need a secret to access the helm repository we can use the `helmSecretName` field. This secret will be cloned to secrets under the `BundleDeployment` namespace (same as we did for the OCI storage secret handling). The PR includes unit, integration (most of code is tested this way) and just one single e2e test so far just to test the whole feature together in a real cluster. Note: This is an experimental feature. In order to activate the `HelmApp` reconciling and `Bundle` deployment you need to the the environment variable: `EXPERIMENTAL_HELM_OPS=true` Refers to: rancher#2962
5324f8f
to
4ad653a
Compare
Signed-off-by: Xavi Garcia <[email protected]>
This is so we can enable the UI and browse artifacts Signed-off-by: Xavi Garcia <[email protected]>
Signed-off-by: Xavi Garcia <[email protected]>
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 this! Leaving a few comments, many of which are just nitpicks.
This new feature creates bundles synchronously, which may be fine for now as they are more lightweight, without resources, than in the gitOps case. But I wonder if that may become an issue on larger setups (although worker counts will soon be configurable event in the agent).
{{- end -}} | ||
|
||
{{ range $shard := $shards }} | ||
{{- if has (dict "name" "EXPERIMENTAL_HELM_OPS" "value" "true") $.Values.extraEnv }} |
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: As discussed offline, this condition could be moved out of the loop over shards, and something similar could be done to the check on $.Values.gitops.enabled
in the gitjob
deployment.
resources: | ||
- 'events' | ||
verbs: | ||
- '*' |
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: do we need all verbs here? Wouldn't create
be enough?
(I'm aware that this probably applies to gitjob and perhaps other RBAC definitions in the fleet
chart as well)
} else { | ||
if auth.InsecureSkipVerify { |
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:
} else { | |
if auth.InsecureSkipVerify { | |
} else if auth.InsecureSkipVerify { | |
// one fewer level of indentation |
@@ -166,7 +166,7 @@ func readFleetIgnore(path string) ([]string, error) { | |||
return ignored, nil | |||
} | |||
|
|||
func loadDirectory(ctx context.Context, compress bool, disableDepsUpdate bool, prefix, base, source, version string, auth Auth) ([]fleet.BundleResource, error) { | |||
func LoadDirectory(ctx context.Context, compress bool, disableDepsUpdate bool, prefix, base, source, version string, auth Auth) ([]fleet.BundleResource, error) { |
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 does this function need to be exported?
internal/bundlereader/charturl.go
Outdated
// inspecting the repo's index.yaml | ||
func chartURL(location *fleet.HelmOptions, auth Auth) (string, error) { | ||
// repos are not supported in case of OCI Charts | ||
func ChartURLVersion(location fleet.HelmOptions, auth Auth) (string, string, error) { |
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 that we're able to return both URL and version, that seems useful. However, do we ever need to fetch both at once? A brief look at calls suggests that we may not.
func checksumPrefix(helm *fleet.HelmOptions) string { | ||
if helm == nil { | ||
return "none" | ||
} | ||
return fmt.Sprintf(".chart/%x", sha256.Sum256([]byte(helm.Chart + ":" + helm.Repo + ":" + helm.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.
Why reimplement this logic, instead of exporting and using bundlereader.checksum
?
} | ||
|
||
func randHelmOptions() *fleet.HelmOptions { | ||
// release name "mqMitPLkEI" |
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.
äh? Is this a leftover from a debugging session? :)
} | ||
|
||
DeferCleanup(func() { | ||
Expect(k8sClient.Delete(ctx, nsSpec)).ToNot(HaveOccurred()) |
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: since not all test cases do it:
Expect(k8sClient.Delete(ctx, nsSpec)).ToNot(HaveOccurred()) | |
Expect(k8sClient.Delete(ctx, nsSpec)).ToNot(HaveOccurred()) | |
_ = k8sClient.Delete(ctx, helmApp) |
} | ||
}) | ||
|
||
It("creates a bundle with the expected spec and the targets and customization merged", func() { |
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 we keep this behaviour, we'll want to document it. Fleet's docs website currently states that:
The targetCustomizations: in fleet.yaml override Helm values only and do not change targeting.
Granted, that's for fleet.yaml
, hence GitRepo
s, but we may end up with 2 config directives named identically but which behave differently depending on the source of truth (git vs Helm).
helmapp.Spec.Helm.Chart = "alpine" | ||
}) | ||
|
||
It("creates a bundle with the latest version it got from the index", func() { |
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! Removing my comment on unit tests about the need to cover this use case 😁
Also: do we want a similar test case for a wildcard version?
Signed-off-by: Xavi Garcia <[email protected]>
eb1967d
to
acc2d99
Compare
This adds a new custom resource
HelmApp
(resource name open to debate) that describes a helm chart to be deployed.The resource contains all the fields from the classic
fleet.yaml
file plus a few new from theGitRepo
resource.HelmApp
yaml example:The implementation tries to share as much as possible from a
Bundle
spec inside the new resource, because it helps to "transform" theHelmApp
into a deployment (no conversion is needed for most of the spec).The new controller was also implemented splitting the functionality into 2 controllers (similar to what we did for the
GitRepo
controller). This allows us to reuse most of the status handling code, as display fields in the status of the new resource are as similar as possible to have consistent user experience and to integrate with the UI in the same way theGitRepo
does.When a new
HelmApp
resource is applied it is transformed into a singleBundle
, adding some extra fields to let theBundle
reconciler know that this is not a regularBundle
coming from aGitRepo
.Similar as we did for OCI storage, the
Bundle
created from aHelmApp
does not contain resources. The helm chart to be deployed is downloaded by the agent.Code for downloading the helm chart is reused from gitops, so the same formats are supported. Insecure TLS skipping was added the the ChartURL and LoadDirectory functions in order to support this for gitops and helmops.
If we need a secret to access the helm repository we can use the
helmSecretName
field. This secret will be cloned to secrets under theBundleDeployment
namespace (same as we did for the OCI storage secret handling).The PR includes unit, integration (most of code is tested this way) and just one single e2e test so far just to test the whole feature together in a real cluster.
The following image describes how Spec fields are shared between
Bundle
andHelmApp
and how the Status fields are shared betweenGitRepo
andHelmApp
:Note: This is an experimental feature. In order to activate the
HelmApp
reconciling andBundle
deployment you need to set the following environment variable:EXPERIMENTAL_HELM_OPS=true
Refers to: #2962