Add local option to annotate
This commit is contained in:
parent
31f415a7be
commit
b86b85dea9
@ -677,6 +677,25 @@ runTests() {
|
|||||||
# Cleanup
|
# Cleanup
|
||||||
kubectl delete pod pod-with-precision "${kube_flags[@]}"
|
kubectl delete pod pod-with-precision "${kube_flags[@]}"
|
||||||
|
|
||||||
|
### Annotate POD YAML file locally without effecting the live pod.
|
||||||
|
kubectl create -f hack/testdata/pod.yaml "${kube_flags[@]}"
|
||||||
|
# Command
|
||||||
|
kubectl annotate -f hack/testdata/pod.yaml annotatekey=annotatevalue "${kube_flags[@]}"
|
||||||
|
|
||||||
|
# Pre-condition: annotationkey is annotationvalue
|
||||||
|
kube::test::get_object_assert 'pod test-pod' "{{${annotations_field}.annotatekey}}" 'annotatevalue'
|
||||||
|
|
||||||
|
# Command
|
||||||
|
output_message=$(kubectl annotate --local -f hack/testdata/pod.yaml annotatekey=localvalue -o yaml "${kube_flags[@]}")
|
||||||
|
echo $output_message
|
||||||
|
|
||||||
|
# Post-condition: annotationkey is still annotationvalue in the live pod, but command output is the new value
|
||||||
|
kube::test::get_object_assert 'pod test-pod' "{{${annotations_field}.annotatekey}}" 'annotatevalue'
|
||||||
|
kube::test::if_has_string "${output_message}" "localvalue"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
kubectl delete -f hack/testdata/pod.yaml "${kube_flags[@]}"
|
||||||
|
|
||||||
### Create valid-pod POD
|
### Create valid-pod POD
|
||||||
# Pre-condition: no POD exists
|
# Pre-condition: no POD exists
|
||||||
create_and_use_new_namespace
|
create_and_use_new_namespace
|
||||||
|
@ -45,6 +45,7 @@ type AnnotateOptions struct {
|
|||||||
selector string
|
selector string
|
||||||
|
|
||||||
overwrite bool
|
overwrite bool
|
||||||
|
local bool
|
||||||
all bool
|
all bool
|
||||||
resourceVersion string
|
resourceVersion string
|
||||||
|
|
||||||
@ -125,6 +126,7 @@ func NewCmdAnnotate(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||||
cmd.Flags().StringVarP(&options.selector, "selector", "l", "", "Selector (label query) to filter on")
|
cmd.Flags().StringVarP(&options.selector, "selector", "l", "", "Selector (label query) to filter on")
|
||||||
cmd.Flags().BoolVar(&options.overwrite, "overwrite", false, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.")
|
cmd.Flags().BoolVar(&options.overwrite, "overwrite", false, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.")
|
||||||
|
cmd.Flags().BoolVar(&options.local, "local", false, "If true, annotation will NOT contact api-server but run locally.")
|
||||||
cmd.Flags().BoolVar(&options.all, "all", false, "select all resources in the namespace of the specified resource types")
|
cmd.Flags().BoolVar(&options.all, "all", false, "select all resources in the namespace of the specified resource types")
|
||||||
cmd.Flags().StringVar(&options.resourceVersion, "resource-version", "", "If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.")
|
cmd.Flags().StringVar(&options.resourceVersion, "resource-version", "", "If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.")
|
||||||
usage := "identifying the resource to update the annotation"
|
usage := "identifying the resource to update the annotation"
|
||||||
@ -167,10 +169,12 @@ func (o *AnnotateOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra
|
|||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam(namespace).DefaultNamespace().
|
NamespaceParam(namespace).DefaultNamespace().
|
||||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||||
SelectorParam(o.selector).
|
Flatten()
|
||||||
ResourceTypeOrNameArgs(o.all, o.resources...).
|
if !o.local {
|
||||||
Flatten().
|
o.builder = o.builder.SelectorParam(o.selector).
|
||||||
Latest()
|
ResourceTypeOrNameArgs(o.all, o.resources...).
|
||||||
|
Latest()
|
||||||
|
}
|
||||||
|
|
||||||
o.f = f
|
o.f = f
|
||||||
o.out = out
|
o.out = out
|
||||||
@ -207,49 +211,56 @@ func (o AnnotateOptions) RunAnnotate() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var outputObj runtime.Object
|
||||||
obj, err := cmdutil.MaybeConvertObject(info.Object, info.Mapping.GroupVersionKind.GroupVersion(), info.Mapping)
|
obj, err := cmdutil.MaybeConvertObject(info.Object, info.Mapping.GroupVersionKind.GroupVersion(), info.Mapping)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
name, namespace := info.Name, info.Namespace
|
if o.local {
|
||||||
oldData, err := json.Marshal(obj)
|
if err := o.updateAnnotations(obj); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
}
|
outputObj = obj
|
||||||
// If we should record change-cause, add it to new annotations
|
|
||||||
if cmdutil.ContainsChangeCause(info) || o.recordChangeCause {
|
|
||||||
o.newAnnotations[kubectl.ChangeCauseAnnotation] = o.changeCause
|
|
||||||
}
|
|
||||||
if err := o.updateAnnotations(obj); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
newData, err := json.Marshal(obj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
|
|
||||||
createdPatch := err == nil
|
|
||||||
if err != nil {
|
|
||||||
glog.V(2).Infof("couldn't compute patch: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mapping := info.ResourceMapping()
|
|
||||||
client, err := o.f.ClientForMapping(mapping)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
helper := resource.NewHelper(client, mapping)
|
|
||||||
|
|
||||||
var outputObj runtime.Object
|
|
||||||
if createdPatch {
|
|
||||||
outputObj, err = helper.Patch(namespace, name, api.StrategicMergePatchType, patchBytes)
|
|
||||||
} else {
|
} else {
|
||||||
outputObj, err = helper.Replace(namespace, name, false, obj)
|
name, namespace := info.Name, info.Namespace
|
||||||
}
|
oldData, err := json.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// If we should record change-cause, add it to new annotations
|
||||||
|
if cmdutil.ContainsChangeCause(info) || o.recordChangeCause {
|
||||||
|
o.newAnnotations[kubectl.ChangeCauseAnnotation] = o.changeCause
|
||||||
|
}
|
||||||
|
if err := o.updateAnnotations(obj); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newData, err := json.Marshal(obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
|
||||||
|
createdPatch := err == nil
|
||||||
|
if err != nil {
|
||||||
|
glog.V(2).Infof("couldn't compute patch: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping := info.ResourceMapping()
|
||||||
|
client, err := o.f.ClientForMapping(mapping)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
helper := resource.NewHelper(client, mapping)
|
||||||
|
|
||||||
|
if createdPatch {
|
||||||
|
outputObj, err = helper.Patch(namespace, name, api.StrategicMergePatchType, patchBytes)
|
||||||
|
} else {
|
||||||
|
outputObj, err = helper.Replace(namespace, name, false, obj)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
mapper, _ := o.f.Object()
|
mapper, _ := o.f.Object()
|
||||||
outputFormat := cmdutil.GetFlagString(o.cmd, "output")
|
outputFormat := cmdutil.GetFlagString(o.cmd, "output")
|
||||||
if outputFormat != "" {
|
if outputFormat != "" {
|
||||||
|
@ -517,6 +517,34 @@ func TestAnnotateObjectFromFile(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAnnotateLocal(t *testing.T) {
|
||||||
|
f, tf, _, ns := NewAPIFactory()
|
||||||
|
tf.Client = &fake.RESTClient{
|
||||||
|
NegotiatedSerializer: ns,
|
||||||
|
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||||
|
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
|
||||||
|
return nil, nil
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
tf.Namespace = "test"
|
||||||
|
tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Default.GroupVersion()}}
|
||||||
|
|
||||||
|
buf := bytes.NewBuffer([]byte{})
|
||||||
|
cmd := NewCmdAnnotate(f, buf)
|
||||||
|
options := &AnnotateOptions{local: true}
|
||||||
|
options.Filenames = []string{"../../../examples/storage/cassandra/cassandra-controller.yaml"}
|
||||||
|
args := []string{"a=b"}
|
||||||
|
if err := options.Complete(f, buf, cmd, args); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if err := options.Validate(args); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if err := options.RunAnnotate(); err != nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAnnotateMultipleObjects(t *testing.T) {
|
func TestAnnotateMultipleObjects(t *testing.T) {
|
||||||
pods, _, _ := testData()
|
pods, _, _ := testData()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user