Added commands to set meta data, like owner, group and permissions of key.
This commit is contained in:
194
main.go
194
main.go
@@ -9,6 +9,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -313,6 +314,134 @@ func (c *KVSClient) handleDelete(args []string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleMeta is the dispatcher for "meta" sub-commands
|
||||||
|
func (c *KVSClient) handleMeta(args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
fmt.Println(red("Usage: meta <get|set> [options]"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
subCmd := args[0]
|
||||||
|
switch subCmd {
|
||||||
|
case "get":
|
||||||
|
c.handleMetaGet(args[1:])
|
||||||
|
case "set":
|
||||||
|
c.handleMetaSet(args[1:])
|
||||||
|
default:
|
||||||
|
fmt.Println(red("Unknown meta command:"), subCmd)
|
||||||
|
fmt.Println("Available commands: get, set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleMetaGet fetches and displays metadata for a key
|
||||||
|
func (c *KVSClient) handleMetaGet(args []string) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
fmt.Println(red("Usage: meta get <key>"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
key := args[0]
|
||||||
|
|
||||||
|
respBody, status, err := c.doRequest("GET", "/kv/"+key+"/metadata", nil)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status == http.StatusNotFound {
|
||||||
|
fmt.Println(yellow("No metadata found for key:"), key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error getting metadata (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct to parse the metadata response
|
||||||
|
type MetaResponse struct {
|
||||||
|
OwnerUUID string `json:"owner_uuid"`
|
||||||
|
GroupUUID string `json:"group_uuid"`
|
||||||
|
Permissions int `json:"permissions"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
UpdatedAt int64 `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var meta MetaResponse
|
||||||
|
if err := json.Unmarshal(respBody, &meta); err != nil {
|
||||||
|
fmt.Println(red("Error parsing metadata response:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(cyan("Metadata for key:"), key)
|
||||||
|
fmt.Printf(" Owner UUID: %s\n", meta.OwnerUUID)
|
||||||
|
fmt.Printf(" Group UUID: %s\n", meta.GroupUUID)
|
||||||
|
fmt.Printf(" Permissions: %d\n", meta.Permissions)
|
||||||
|
fmt.Printf(" Created At: %s\n", time.Unix(meta.CreatedAt, 0).Format(time.RFC3339))
|
||||||
|
fmt.Printf(" Updated At: %s\n", time.Unix(meta.UpdatedAt, 0).Format(time.RFC3339))
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleMetaSet updates metadata for a key using flags
|
||||||
|
func (c *KVSClient) handleMetaSet(args []string) {
|
||||||
|
if len(args) < 3 {
|
||||||
|
fmt.Println(red("Usage: meta set <key> --owner <uuid> | --group <uuid> | --permissions <number>"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
key := args[0]
|
||||||
|
|
||||||
|
// Use a map to build the JSON payload for partial updates
|
||||||
|
payload := make(map[string]interface{})
|
||||||
|
|
||||||
|
// Parse command-line flags
|
||||||
|
for i := 1; i < len(args); i++ {
|
||||||
|
switch args[i] {
|
||||||
|
case "--owner":
|
||||||
|
if i+1 < len(args) {
|
||||||
|
payload["owner_uuid"] = args[i+1]
|
||||||
|
i++ // Skip the value
|
||||||
|
}
|
||||||
|
case "--group":
|
||||||
|
if i+1 < len(args) {
|
||||||
|
payload["group_uuid"] = args[i+1]
|
||||||
|
i++ // Skip the value
|
||||||
|
}
|
||||||
|
case "--permissions":
|
||||||
|
if i+1 < len(args) {
|
||||||
|
perms, err := strconv.Atoi(args[i+1])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Invalid permissions value:"), args[i+1])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
payload["permissions"] = perms
|
||||||
|
i++ // Skip the value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(payload) == 0 {
|
||||||
|
fmt.Println(red("No valid metadata fields provided to set."))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody, status, err := c.doRequest("PUT", "/kv/"+key+"/metadata", payload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error setting metadata (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(green("Metadata updated successfully for key:"), key)
|
||||||
|
// The response body contains the full updated metadata, so we can print it for confirmation
|
||||||
|
var pretty bytes.Buffer
|
||||||
|
json.Indent(&pretty, respBody, "", " ")
|
||||||
|
fmt.Println(pretty.String())
|
||||||
|
}
|
||||||
|
|
||||||
func (c *KVSClient) handleMembers(args []string) {
|
func (c *KVSClient) handleMembers(args []string) {
|
||||||
respBody, status, err := c.doRequest("GET", "/members/", nil)
|
respBody, status, err := c.doRequest("GET", "/members/", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -408,6 +537,43 @@ func (c *KVSClient) handleUserGet(args []string) {
|
|||||||
fmt.Printf(" Updated: %s\n", time.Unix(user.UpdatedAt, 0).Format(time.RFC3339))
|
fmt.Printf(" Updated: %s\n", time.Unix(user.UpdatedAt, 0).Format(time.RFC3339))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *KVSClient) handleUserCreate(args []string) {
|
||||||
|
if len(args) < 1 {
|
||||||
|
fmt.Println(red("Usage: user create <nickname>"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The request body requires a JSON object like {"nickname": "..."}
|
||||||
|
requestPayload := map[string]string{
|
||||||
|
"nickname": args[0],
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody, status, err := c.doRequest("POST", "/api/users", requestPayload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(red("Error:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The backend returns 200 OK on success
|
||||||
|
if status != http.StatusOK {
|
||||||
|
fmt.Printf(red("Error creating user (status %d):\n"), status)
|
||||||
|
fmt.Println(string(respBody))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the successful response to get the new user's UUID
|
||||||
|
var response struct {
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(respBody, &response); err != nil {
|
||||||
|
fmt.Println(red("Error parsing successful response:"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(green("User created successfully"))
|
||||||
|
fmt.Println(cyan("UUID:"), response.UUID)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *KVSClient) handleHelp(args []string) {
|
func (c *KVSClient) handleHelp(args []string) {
|
||||||
help := `
|
help := `
|
||||||
KVS Interactive Shell - Available Commands:
|
KVS Interactive Shell - Available Commands:
|
||||||
@@ -425,6 +591,11 @@ Key-Value Operations:
|
|||||||
put <key> <json> - Store JSON value at key
|
put <key> <json> - Store JSON value at key
|
||||||
delete <key> - Delete key
|
delete <key> - Delete key
|
||||||
|
|
||||||
|
Resource Metadata:
|
||||||
|
meta get <key> - Get metadata (owner, group) for a key
|
||||||
|
meta set <key> [flags] - Set metadata for a key
|
||||||
|
Flags: --owner <uuid>, --group <uuid>, --permissions <number>
|
||||||
|
|
||||||
Cluster Management:
|
Cluster Management:
|
||||||
members - List cluster members
|
members - List cluster members
|
||||||
health - Check service health
|
health - Check service health
|
||||||
@@ -500,14 +671,25 @@ func main() {
|
|||||||
client.handlePut(args)
|
client.handlePut(args)
|
||||||
case "delete":
|
case "delete":
|
||||||
client.handleDelete(args)
|
client.handleDelete(args)
|
||||||
|
case "meta":
|
||||||
|
client.handleMeta(args)
|
||||||
case "members":
|
case "members":
|
||||||
client.handleMembers(args)
|
client.handleMembers(args)
|
||||||
case "health":
|
case "health":
|
||||||
client.handleHealth(args)
|
client.handleHealth(args)
|
||||||
case "user":
|
case "user":
|
||||||
if len(args) > 0 && args[0] == "get" {
|
if len(args) > 0 {
|
||||||
client.handleUserGet(args[1:])
|
switch args[0] {
|
||||||
|
case "get":
|
||||||
|
client.handleUserGet(args[1:])
|
||||||
|
case "create":
|
||||||
|
client.handleUserCreate(args[1:])
|
||||||
|
default:
|
||||||
|
fmt.Println(red("Unknown user command:"), args[0])
|
||||||
|
fmt.Println("Type 'help' for available commands")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// This was the original behavior, which notes that listing users is not implemented.
|
||||||
client.handleUserList(args)
|
client.handleUserList(args)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -529,6 +711,14 @@ var completer = readline.NewPrefixCompleter(
|
|||||||
readline.PcItem("get"),
|
readline.PcItem("get"),
|
||||||
readline.PcItem("put"),
|
readline.PcItem("put"),
|
||||||
readline.PcItem("delete"),
|
readline.PcItem("delete"),
|
||||||
|
readline.PcItem("meta",
|
||||||
|
readline.PcItem("get"),
|
||||||
|
readline.PcItem("set",
|
||||||
|
readline.PcItem("--owner"),
|
||||||
|
readline.PcItem("--group"),
|
||||||
|
readline.PcItem("--permissions"),
|
||||||
|
),
|
||||||
|
),
|
||||||
readline.PcItem("members"),
|
readline.PcItem("members"),
|
||||||
readline.PcItem("health"),
|
readline.PcItem("health"),
|
||||||
readline.PcItem("user",
|
readline.PcItem("user",
|
||||||
|
Reference in New Issue
Block a user