-
Notifications
You must be signed in to change notification settings - Fork 38.6k
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 apply set-last-applied subcommand #41694
Conversation
Hi @shiywang. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
0a2c435
to
1b40c42
Compare
why cc @kubernetes/sig-cli-pr-reviews doesn't assign to right people ? |
cc'ing doesn't set the reviewers, it just makes sure the right people get notified. |
"k8s.io/kubernetes/pkg/kubectl/resource" | ||
) | ||
|
||
type SetLastAppliedOptions struct { |
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 code snippet duplicate with view-last-applied
, can refactor if that get merged.
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.
ok, I'll refactor it when all sub-commands get merged.
Long: applySetLastAppliedLong, | ||
Example: applySetLastAppliedExample, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
cmdutil.CheckErr(options.RunApplySetLastApplied(f, args, cmd, out, err, options)) |
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 would like this also follow Complete
Validate
and Run
convention.
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.
forget that convention again, yuck.... will update soon
return cmd | ||
} | ||
|
||
func (o *SetLastAppliedOptions) RunApplySetLastApplied(f cmdutil.Factory, args []string, cmd *cobra.Command, out, errOut io.Writer, options *SetLastAppliedOptions) 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.
pls avoid direct cobra dependency.
|
||
applySetLastAppliedExample = templates.Examples(` | ||
# Set the current file's content to the latest-applied-configuration of this resource. | ||
kubectl apply set-last-applied -f deploy.yaml`) |
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.
which resource to be updated? identified by deploy.yaml?
annotationsMap[annotations.LastAppliedConfigAnnotation] = string(localFile) | ||
metadataMap["annotations"] = annotationsMap | ||
objMap["metadata"] = metadataMap | ||
jsonString, err := json.Marshal(objMap) |
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 am afraid this is not correct here, we should calculate the final patch between the current object and object with annotation updated.
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.
so, it's like run apply -f
first, get the result object then calculate the final patch between current object and the result object I got before ? currently I think I just set the file's object to annotations then do a json-merge-patch
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.
@adohe What is the result of the incorrect behavior? AFAICT this send just a regular mergepatch with the single annotation instead of calculating the full diff between objects. Is this incorrect or just not the recommended style?
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.
generally this does the same thing as kubectl annotate
, i would think the way annotate
use is more clean.
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.
@adohe Hm. I am not sure I totally agree. WDYT of of leaving it as is for now, so this makes feature freeze (tomorrow), and we can follow up if we decide we want to change it.
} | ||
} | ||
|
||
if !dryRun { |
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.
should add dry-run
handling.
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.
Should dryrun just print out the patch string that would be sent? Does dryrun make sense in this context at all? WDYT @adohe ?
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.
dry-run
means just print the object that would be sent~yep that would make sense print out the patch when dry-run
if err != nil { | ||
return err | ||
} | ||
annotationsMap[annotations.LastAppliedConfigAnnotation] = string(localFile) |
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 there are no changes, we shouldn't do a patch
} | ||
|
||
if cmdutil.ShouldRecord(cmd, info) { | ||
if patch, patchType, err := cmdutil.ChangeResourcePatch(info, f.Command()); err == nil { |
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 is this a separate patch command instead of part of the first patch command?
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 am not really sure we should update this at all since it isn't updating the object itself. Lets not do this for now.
return err | ||
} | ||
|
||
if cmdutil.ShouldRecord(cmd, info) { |
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.
Add a comment
|
||
var ( | ||
applySetLastAppliedLong = templates.LongDesc(` | ||
Set the latest last-applied-configuration annotations by file.`) |
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.
Set the latest last-applied-configuration annotations by setting it to match the contents of a file. This results in the last-applied-configuration being updated as though 'kubectl apply -f <file>' was run, without updating any other parts of the object.
Set the latest last-applied-configuration annotations by file.`) | ||
|
||
applySetLastAppliedExample = templates.Examples(` | ||
# Set the current file's content to the latest-applied-configuration of this resource. |
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.
Set the last-applied-configuration of a resource to match the contents of a file.
annotationsMap[annotations.LastAppliedConfigAnnotation] = string(localFile) | ||
metadataMap["annotations"] = annotationsMap | ||
objMap["metadata"] = metadataMap | ||
jsonString, err := json.Marshal(objMap) |
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.
@adohe What is the result of the incorrect behavior? AFAICT this send just a regular mergepatch with the single annotation instead of calculating the full diff between objects. Is this incorrect or just not the recommended style?
return err | ||
} | ||
|
||
objMap := map[string]map[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.
plz pull the patch calculation into its own function. e.g.
func (o *SetLastAppliedOptions) getPatch(info) string, error {
...
return json.Marshal(objMap)
}
return err | ||
} | ||
|
||
if err := info.Get(); err != nil { |
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.
pull this into the validation function. Add a comment explaining why we do this.
// Verify the object exists in the cluster before trying to patch it.
} | ||
} | ||
|
||
if !dryRun { |
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.
Should dryrun just print out the patch string that would be sent? Does dryrun make sense in this context at all? WDYT @adohe ?
pkg/kubectl/cmd/apply_test.go
Outdated
filenameRC = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc.yaml" | ||
filenameSVC = "../../../test/fixtures/pkg/kubectl/cmd/apply/service.yaml" | ||
filenameRCSVC = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc-service.yaml" | ||
filenameRC = "../../../test/fixtures/pkg/kubectl/cmd/apply/rc.yaml" |
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.
also add an e2e test that does
kubectl apply -f deployment1.yaml // contains replicas = 2
kubectl apply view-last-applied -f deploymen1.yaml // check the last-applied matches expectations
kubectl apply set-last-applied -f deployment2.yaml // doesn't have replicas
kubectl apply view-last-applied -f deploymen1.yaml // check last-applied has been updated
kubectl scale deployment ... // set replicas = 3
kubectl apply -f deployment3.yaml // doesn't have replicas, and changes the images
kubectl get -f deployment3.yaml // verify replicas still = 3 and image has been updated
@pwittrock I am wondering whether we should allow set |
760a00b
to
b0c0ff2
Compare
@shiywang Please rebase to resolve conflicts. |
@pwittrock ok, great, will do that |
options := &SetLastAppliedOptions{Out: out, ErrOut: err} | ||
cmd := &cobra.Command{ | ||
Use: "set-last-applied -f FILENAME", | ||
Short: "Set latest last-applied-configuration annotations of by file", |
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.
Awkward language. Use:
Set the last-applied-configuration annotation on a live object to match the contents of a file.
# Set the last-applied-configuration of a resource to match the contents of a file. | ||
kubectl apply set-last-applied -f deploy.yaml | ||
|
||
# Set the last-applied-configuration of resourcesto match the contents of files in a directory. |
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.
typo + awkward:
Execute set-last-applied against each configuration file in a directory.
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err) | ||
} | ||
if oringalBuf == nil { | ||
return cmdutil.AddSourceToErr(fmt.Sprintf("no last-applied-configuration annotation found on resource: %s\n", info.Name), info.Source, 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.
Lets add a flag --create-annotation
that will allow this to be set if it is missing. Default should be false.
o.PatchBufferList = append(o.PatchBufferList, patchBuf) | ||
o.InfoList = append(o.InfoList, info) | ||
} else { | ||
fmt.Fprintf(o.Out, "set-last-applied %s: no valid changes saved, won't be patch\n", info.Name) |
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.
Awkward:
set-last-applied %s: no changes required.\n
pkg/kubectl/cmd/apply_test.go
Outdated
expectedOut: "replicationcontroller/test-rc\n", | ||
}, | ||
{ | ||
name: "set with no-exist 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.
Add test for the annotation does not exist on the live object.
{ | ||
name: "set with no-exist object", | ||
filePath: filenameNoExistRC, | ||
expectedErr: "Error from server (NotFound): the server could not find the requested resource (get replicationcontrollers no-exist)", |
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.
Add test for a json file
{ | ||
name: "set with no-exist object", | ||
filePath: filenameNoExistRC, | ||
expectedErr: "Error from server (NotFound): the server could not find the requested resource (get replicationcontrollers no-exist)", |
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.
Add test for a directory of files
# Set the last-applied-configuration of resourcesto match the contents of files in a directory. | ||
kubectl apply set-last-applied -f path/ | ||
|
||
# Set the last-applied-configuration of a resource to match the contents of a file, will create if resource doesn't have one. |
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 create the annotation if it does not already exist
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err) | ||
} | ||
if oringalBuf == nil && !o.CreateAnnotation { | ||
return cmdutil.UsageError(cmd, "no last-applied-configuration annotation found on resource: %s, please use '--create-annotation' to create one", info.Name) |
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.
please use '--create-annotation' to create one
How about
to create the annotation, run the command with --create-annotation
@pwittrock ptal ? |
@k8s-bot test this |
@shiywang: you can't request testing unless you are a kubernetes member. In response to this comment:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
@pwittrock hi, just can not reach you on slack, sorry, just forgot update bazel last night, could you please let bot tests again ? |
@k8s-bot ok to test |
update update code update unit tests hack/update remove spew update bazel updated add comments remove unused parameter remove hardcode bump unit tests add new flags add unit tests add bazel genreate doc
@pwittrock docs genreated, ptal |
@k8s-bot unit test this |
/lgtm |
/approve |
[APPROVALNOTIFIER] This PR is APPROVED The following people have approved this PR: pwittrock, shiywang Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
Automatic merge from submit-queue (batch tested with PRs 42044, 41694, 41927, 42050, 41987) |
implement part of kubernetes/community#287, will rebase after #41699 got merged, EDIT: since bug output format has been confirmed, will update the behavior of output format soon
cc @kubernetes/sig-cli-pr-reviews @adohe @pwittrock