mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	improve kv CLI to remove data or custom metadata using kv patch (#18067)
* improve kv CLI to remove data or custom metadata using kv patch * CL * adding a comment
This commit is contained in:
		
							
								
								
									
										3
									
								
								changelog/18067.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								changelog/18067.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | ```release-note:improvement | ||||||
|  | cli/kv: improve kv CLI to remove data or custom metadata using kv patch | ||||||
|  | ``` | ||||||
| @@ -24,6 +24,7 @@ type KVMetadataPatchCommand struct { | |||||||
| 	flagCASRequired          BoolPtr | 	flagCASRequired          BoolPtr | ||||||
| 	flagDeleteVersionAfter   time.Duration | 	flagDeleteVersionAfter   time.Duration | ||||||
| 	flagCustomMetadata       map[string]string | 	flagCustomMetadata       map[string]string | ||||||
|  | 	flagRemoveCustomMetadata []string | ||||||
| 	flagMount                string | 	flagMount                string | ||||||
| 	testStdin                io.Reader // for tests | 	testStdin                io.Reader // for tests | ||||||
| } | } | ||||||
| @@ -65,6 +66,10 @@ Usage: vault kv metadata patch [options] KEY | |||||||
|  |  | ||||||
|       $ vault kv metadata patch -mount=secret -custom-metadata=foo=abc -custom-metadata=bar=123 foo |       $ vault kv metadata patch -mount=secret -custom-metadata=foo=abc -custom-metadata=bar=123 foo | ||||||
|  |  | ||||||
|  |   To remove custom meta data from the corresponding path in the key-value store, kv metadata patch can be used. | ||||||
|  |  | ||||||
|  |       $ vault kv metadata patch -mount=secret -remove-custom-metadata=bar foo | ||||||
|  |  | ||||||
|   Additional flags and more advanced use cases are detailed below. |   Additional flags and more advanced use cases are detailed below. | ||||||
|  |  | ||||||
| ` + c.Flags().Help() | ` + c.Flags().Help() | ||||||
| @@ -111,6 +116,13 @@ func (c *KVMetadataPatchCommand) Flags() *FlagSets { | |||||||
| 		This can be specified multiple times to add multiple pieces of metadata.`, | 		This can be specified multiple times to add multiple pieces of metadata.`, | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
|  | 	f.StringSliceVar(&StringSliceVar{ | ||||||
|  | 		Name:    "remove-custom-metadata", | ||||||
|  | 		Target:  &c.flagRemoveCustomMetadata, | ||||||
|  | 		Default: []string{}, | ||||||
|  | 		Usage:   "Key to remove from custom metadata. To specify multiple values, specify this flag multiple times.", | ||||||
|  | 	}) | ||||||
|  |  | ||||||
| 	f.StringVar(&StringVar{ | 	f.StringVar(&StringVar{ | ||||||
| 		Name:    "mount", | 		Name:    "mount", | ||||||
| 		Target:  &c.flagMount, | 		Target:  &c.flagMount, | ||||||
| @@ -198,7 +210,7 @@ func (c *KVMetadataPatchCommand) Run(args []string) int { | |||||||
|  |  | ||||||
| 	fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata") | 	fullPath := addPrefixToKVPath(partialPath, mountPath, "metadata") | ||||||
|  |  | ||||||
| 	data := map[string]interface{}{} | 	data := make(map[string]interface{}, 0) | ||||||
|  |  | ||||||
| 	if c.flagMaxVersions >= 0 { | 	if c.flagMaxVersions >= 0 { | ||||||
| 		data["max_versions"] = c.flagMaxVersions | 		data["max_versions"] = c.flagMaxVersions | ||||||
| @@ -212,10 +224,19 @@ func (c *KVMetadataPatchCommand) Run(args []string) int { | |||||||
| 		data["delete_version_after"] = c.flagDeleteVersionAfter.String() | 		data["delete_version_after"] = c.flagDeleteVersionAfter.String() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if len(c.flagCustomMetadata) > 0 { | 	customMetadata := make(map[string]interface{}) | ||||||
| 		data["custom_metadata"] = c.flagCustomMetadata |  | ||||||
|  | 	for key, value := range c.flagCustomMetadata { | ||||||
|  | 		customMetadata[key] = value | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	for _, key := range c.flagRemoveCustomMetadata { | ||||||
|  | 		// A null in a JSON merge patch payload will remove the associated key | ||||||
|  | 		customMetadata[key] = nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	data["custom_metadata"] = customMetadata | ||||||
|  |  | ||||||
| 	secret, err := client.Logical().JSONMergePatch(context.Background(), fullPath, data) | 	secret, err := client.Logical().JSONMergePatch(context.Background(), fullPath, data) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		c.UI.Error(fmt.Sprintf("Error writing data to %s: %s", fullPath, err)) | 		c.UI.Error(fmt.Sprintf("Error writing data to %s: %s", fullPath, err)) | ||||||
|   | |||||||
| @@ -122,6 +122,29 @@ func TestKvMetadataPatchCommand_Flags(t *testing.T) { | |||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			"remove-custom_metadata", | ||||||
|  | 			[]string{"-custom-metadata=baz=ghi", "-remove-custom-metadata=foo"}, | ||||||
|  | 			"Success!", | ||||||
|  | 			0, | ||||||
|  | 			map[string]interface{}{ | ||||||
|  | 				"custom_metadata": map[string]interface{}{ | ||||||
|  | 					"bar": "def", | ||||||
|  | 					"baz": "ghi", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			"remove-custom_metadata-multiple", | ||||||
|  | 			[]string{"-custom-metadata=baz=ghi", "-remove-custom-metadata=foo", "-remove-custom-metadata=bar"}, | ||||||
|  | 			"Success!", | ||||||
|  | 			0, | ||||||
|  | 			map[string]interface{}{ | ||||||
|  | 				"custom_metadata": map[string]interface{}{ | ||||||
|  | 					"baz": "ghi", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"delete_version_after_success", | 			"delete_version_after_success", | ||||||
| 			[]string{"-delete-version-after=5s"}, | 			[]string{"-delete-version-after=5s"}, | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ type KVPatchCommand struct { | |||||||
| 	flagMethod     string | 	flagMethod     string | ||||||
| 	flagMount      string | 	flagMount      string | ||||||
| 	testStdin      io.Reader // for tests | 	testStdin      io.Reader // for tests | ||||||
|  | 	flagRemoveData []string | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *KVPatchCommand) Synopsis() string { | func (c *KVPatchCommand) Synopsis() string { | ||||||
| @@ -76,6 +77,10 @@ Usage: vault kv patch [options] KEY [DATA] | |||||||
|  |  | ||||||
|       $ vault kv patch -mount=secret -method=rw foo bar=baz |       $ vault kv patch -mount=secret -method=rw foo bar=baz | ||||||
|  |  | ||||||
|  |   To remove data from the corresponding path in the key-value store, kv patch can be used. | ||||||
|  |  | ||||||
|  |       $ vault kv patch -mount=secret -remove-data=bar foo | ||||||
|  |  | ||||||
|   Additional flags and more advanced use cases are detailed below. |   Additional flags and more advanced use cases are detailed below. | ||||||
|  |  | ||||||
| ` + c.Flags().Help() | ` + c.Flags().Help() | ||||||
| @@ -117,6 +122,13 @@ func (c *KVPatchCommand) Flags() *FlagSets { | |||||||
| 		v2 secrets.`, | 		v2 secrets.`, | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
|  | 	f.StringSliceVar(&StringSliceVar{ | ||||||
|  | 		Name:    "remove-data", | ||||||
|  | 		Target:  &c.flagRemoveData, | ||||||
|  | 		Default: []string{}, | ||||||
|  | 		Usage:   "Key to remove from data. To specify multiple values, specify this flag multiple times.", | ||||||
|  | 	}) | ||||||
|  |  | ||||||
| 	return set | 	return set | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -147,7 +159,7 @@ func (c *KVPatchCommand) Run(args []string) int { | |||||||
| 	case len(args) < 1: | 	case len(args) < 1: | ||||||
| 		c.UI.Error(fmt.Sprintf("Not enough arguments (expected >1, got %d)", len(args))) | 		c.UI.Error(fmt.Sprintf("Not enough arguments (expected >1, got %d)", len(args))) | ||||||
| 		return 1 | 		return 1 | ||||||
| 	case len(args) == 1: | 	case len(c.flagRemoveData) == 0 && len(args) == 1: | ||||||
| 		c.UI.Error("Must supply data") | 		c.UI.Error("Must supply data") | ||||||
| 		return 1 | 		return 1 | ||||||
| 	} | 	} | ||||||
| @@ -211,6 +223,16 @@ func (c *KVPatchCommand) Run(args []string) int { | |||||||
| 		return 2 | 		return 2 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	// collecting data to be removed | ||||||
|  | 	if newData == nil { | ||||||
|  | 		newData = make(map[string]interface{}) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, key := range c.flagRemoveData { | ||||||
|  | 		// A null in a JSON merge patch payload will remove the associated key | ||||||
|  | 		newData[key] = nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// Check the method and behave accordingly | 	// Check the method and behave accordingly | ||||||
| 	var secret *api.Secret | 	var secret *api.Secret | ||||||
| 	var code int | 	var code int | ||||||
|   | |||||||
| @@ -249,6 +249,7 @@ func TestKV_Patch_RootToken(t *testing.T) { | |||||||
| 		data := map[string]interface{}{ | 		data := map[string]interface{}{ | ||||||
| 			"data": map[string]interface{}{ | 			"data": map[string]interface{}{ | ||||||
| 				"bar": "baz", | 				"bar": "baz", | ||||||
|  | 				"foo": "qux", | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -263,6 +264,7 @@ func TestKV_Patch_RootToken(t *testing.T) { | |||||||
| 		data := map[string]interface{}{ | 		data := map[string]interface{}{ | ||||||
| 			"data": map[string]interface{}{ | 			"data": map[string]interface{}{ | ||||||
| 				"bar": "quux", | 				"bar": "quux", | ||||||
|  | 				"foo": nil, | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
| 		return client.Logical().JSONMergePatch(context.Background(), "kv/data/foo", data) | 		return client.Logical().JSONMergePatch(context.Background(), "kv/data/foo", data) | ||||||
| @@ -288,4 +290,8 @@ func TestKV_Patch_RootToken(t *testing.T) { | |||||||
| 	if bar != "quux" { | 	if bar != "quux" { | ||||||
| 		t.Fatalf("expected bar to be quux but it was %q", bar) | 		t.Fatalf("expected bar to be quux but it was %q", bar) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if _, ok := secret.Data["data"].(map[string]interface{})["foo"]; ok { | ||||||
|  | 		t.Fatalf("expected data not to include foo") | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Hamid Ghaf
					Hamid Ghaf