-
Notifications
You must be signed in to change notification settings - Fork 110
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
Support for server side apply #392
base: develop
Are you sure you want to change the base?
Conversation
Thanks for the draft PR @redbaron ! |
|
||
if existingRes != nil { | ||
// Strip rebasing "base" object of kapp history so that it never shows up in the diff, regardless | ||
// of rebase rules used | ||
existingResForRebasing, err = f.NewResourceWithHistory(existingRes).HistorylessResource() |
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 believe there was a sleeper bug here, which unfolded like following:
- By the end of this function
existingRes
was unconditionally stripped of history withHistorylessResource()
newRes
was unconditionally stripped of history withHistorylessResource()
existingResForRebasing
has history kept, because it comes from the cluster as is- When building
rebasedNewRes
usingexistingResForRebasing + newRes
, history was removed due to default rebase rules included in the kapp transplanting history-less annotations fromnewRes
- If we redeploy same object as previous deployment, end result has no spurious diff, because both objects have history stripped
Should provided config had different rebase rules, rebasedNewRes
is going to have history annotations from existingResForRebasing
, but existingRes
wont, generating spurious diff.
Similar situation arises when metadata.managedFields
is populated by the cluster. This field is considered history and is stripped in HistorylessResource()
call, but default rebase rules have no mentions of it.
Instead of updating default rebase rule, I opted for fixing it at the source. Here I am stripping history from all objects, ensuring it is not going to show up in any diffs regardless of kapp config provided. Technically it is a change in behaviour, hence this comment to highlight it.
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.
will think through it, thanks for call out 👍
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.
to double check -- changes in NewChangeAgainstLastApplied are not really affecting SSA, right? (i might have to ask to separate them out into a diff PR).
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.
looking pretty good so far.
pkg/kapp/cmd/app/deploy.go
Outdated
if o.ApplyFlags.ServerSideApply { | ||
o.DiffFlags.ChangeSetOpts.Mode = ctldiff.ServerSideApplyChangeSetMode | ||
} |
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 a fan of doing it in RunE, lets move this into Run()... (also going to see if there is a better place for this)
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 plan to add flag validation step and return error, rather than silently overwriting values provided by user, so it should be a RunE I believe because it can return 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 believe we could move these validations to the Run()
function as it returns an error and let the command initialisation have
RunE: func(_ *cobra.Command, _ []string) error { return o.Run() }
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.
Moved to PreRunE
|
||
if existingRes != nil { | ||
// Strip rebasing "base" object of kapp history so that it never shows up in the diff, regardless | ||
// of rebase rules used | ||
existingResForRebasing, err = f.NewResourceWithHistory(existingRes).HistorylessResource() |
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.
will think through it, thanks for call out 👍
pkg/kapp/cmd/app/deploy.go
Outdated
if o.ApplyFlags.ServerSideApply { | ||
o.DiffFlags.ChangeSetOpts.Mode = ctldiff.ServerSideApplyChangeSetMode | ||
} |
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 believe we could move these validations to the Run()
function as it returns an error and let the command initialisation have
RunE: func(_ *cobra.Command, _ []string) error { return o.Run() }
@@ -313,6 +313,8 @@ apiVersion: v1 | |||
kind: ConfigMap | |||
metadata: | |||
name: test-cm | |||
annotations: | |||
ann1: val1 |
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've added this to show that not all annotations stripped when object is passed to rebase rules
@@ -351,15 +353,18 @@ data: | |||
"values": asYAML(t, map[string]interface{}{ | |||
"existing": func() interface{} { | |||
raw := cm.Raw() | |||
removeHistory(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.
Consequence of https://github.com/vmware-tanzu/carvel-kapp/pull/392/files#r768970039 is that rebase rules don't see history in objects passed to them. I've adjusted test to reflect it.
Hm, all tests are passing locally on Docker Desktop managed 1.21 kubernetes cluster, but |
Strategic merge patch is not support for CRDs without schema
OK, it reached the stage where I'd like to propose it for a merge. I added option to run E2E tests with SSA enabled and test suite now passes with SSA on my 1.21 K8S, except for tests with rebasing. I'll go through diff and add notes on parts worth paying attention to.
There is a missing test for /cc @cppforlife |
cool cool. ill do a deep dive today/tomorrow on this @redbaron. other folks will also take a look... |
(still reading through the code... hoping to be done tomorrow) |
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.
looking pretty good. ive left some nit-picks, and a few "designy" changes to hopefully simplify a little bit of code.
// Patch dry run returns merged object with all patch-file fields present | ||
err = kubectl.RunWithOptsIntoJSON([]string{"patch", "svc", "redis-primary", "--patch-file", tmpFile.Name(), "--dry-run=client"}, | ||
RunOpts{IntoNs: true}, &expectedObj) | ||
require.NoError(t, 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.
seems like a complicated way of determining expected state. is there something simpler that can be done (aka more static/hard-coded into the test)?
var err error | ||
|
||
if c.aou.opts.ServerSideApply { | ||
updatedRes, err = ctlres.WithIdentityAnnotation(c.newRes, func(r ctlres.Resource) (ctlres.Resource, 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.
it seems that we have two types of Patch operations: one where we are working with a resource, and one where we are working with some "minimal/raw" patch. instead of exposing WithIdentityAnnotation outside of IdentifiedResources resources class, lets keep existing Patch method to work with Resource class (instead of []byte) and change it so that it can add annotation on the fly. lets also add PatchRaw which does take []byte. this should result in keeping WithIdentityAnnotation as private.
|
||
if existingRes != nil { | ||
// Strip rebasing "base" object of kapp history so that it never shows up in the diff, regardless | ||
// of rebase rules used | ||
existingResForRebasing, err = f.NewResourceWithHistory(existingRes).HistorylessResource() |
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.
to double check -- changes in NewChangeAgainstLastApplied are not really affecting SSA, right? (i might have to ask to separate them out into a diff PR).
type ChangeSetOpts struct { | ||
AgainstLastApplied bool | ||
Mode ChangeSetMode |
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.
after reading through flag "adjusting" above, i think we should just turns this into:
type ChangeSetOpts struct {
ServerSideApply bool
AgainstLastApplied bool
}
anywhere where we are doing a switch based on mode, we should just do:
switch {
case opts.ServerSideApply: ...
case opts.AgainstLastApplied: ...
default: ...
}
the reasoning for this, it seems that mode enum introduces quite a bit of gymanistics necessary to compute what it should be.
@@ -218,5 +211,11 @@ func (resourceWithoutHistory) removeAppliedResAnnKeysMods() []ctlres.ResourceMod | |||
ResourceMatcher: ctlres.AllMatcher{}, | |||
Path: ctlres.NewPathFromStrings([]string{"metadata", "annotations", debugAppliedResDiffFullAnnKey}), | |||
}, | |||
// metadata.managedFields technically is not kapp history, but we want to strip it in same situations we are | |||
// stripping kapp history, it is server side apply history after all | |||
ctlres.FieldRemoveMod{ |
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.
without this, was this breaking anything? (if so, just for ssa, or for non-ssa operation?)
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.
Yes, with SSA enabled it was reporting diff on managedFields
where it shouldn't
Thanks for a quick review, I'll make requested changes shortly |
@redbaron lmk, when to take a look at the PR again. |
Hey guys, Could you give me a brief update on the topic? Are there still plans to support server-side-apply or will there be no further work on this topic for the time being? |
Hi @ebma16! Unfortunately the maintainers don't have the bandwidth to work on this at the moment, and I am not sure when we will be able to prioritise it. We can definitely prioritise a review if you would be interested in submitting a PR or continuing on this one. kapp rebase rules should still work well with other tools that support SSA. Could you share the specific problem that you are facing? |
Hi @praveenrewar, At the moment I have no problems with the kapp rebase rules. We are still in an early phase of the project and I just did a small test for the interaction between the Java-Operator-SDK (using SSA) and the kapp rebase rules (without SSA). So far I could not find any problems and everything worked. I was just curious about the current status when I read this thread ;) I will continue with this constellation (kapp without SSA and other tools using SSA). If I notice any problems, I will definitely let you know and continue this thread! |
Sure, keep us updated. Happy to chat on carvel slack channel too if you need help with anything. |
First take on server side apply feature (#388) to collect early feedback.
Some highlights:
kapp
code paths, so I had to approximate it by diffing existing instances against dry run SSA result. This required calls to K8S much earlier in the code than it was previously, which required some plumbingNewChangeSSA
change factoryKAPP_E2E_SSA=1
env var value. When set,--ssa-enabled
flag is added to kapp invocation allowing same tests to be run in SSA mode. Tests with rebasing are skipped in SSA mode.*corbra.Command
in the testing process. It is not a full replacement for akapp
command execution, but greatly helped developing this feature as most interesting scenarios come up ine2e
and not unit testing.Unimplemented:
--diff-against-last-applied
.Yet untested (unless there is an existing E2E test covering it):
Features deliberately left outside of this PR:
kapp
could assist with it.