// runSetUser invokes the REST API with POST action and username as // path. Prompts for the password twice on stdin. // TODO(marc): once we have more fields in the user config, we will need // to allow changing just some of them (eg: change email, but leave password). func runSetUser(cmd *cobra.Command, args []string) { if len(args) != 1 { cmd.Usage() return } hashed, err := security.PromptForPasswordAndHash() if err != nil { log.Error(err) return } // Build a UserConfig object. RunSetUser expects Yaml. // TODO(marc): re-work admin client library to take other encodings. pb := &proto.UserConfig{HashedPassword: hashed} contents, err := yaml.Marshal(pb) if err != nil { log.Error(err) return } admin := client.NewAdminClient(&Context.Context, Context.Addr, client.User) if err := admin.SetYAML(args[0], string(contents)); err != nil { log.Error(err) return } fmt.Printf("Wrote user config for %q\n", args[0]) }
// runExterminate destroys the data held in the specified stores. func runExterminate(cmd *cobra.Command, args []string) { if err := context.InitStores(); err != nil { log.Errorf("failed to initialize context: %s", err) return } // First attempt to shutdown the server. Note that an error of EOF just // means the HTTP server shutdown before the request to quit returned. admin := client.NewAdminClient(&context.Context, context.Addr, client.Quit) body, err := admin.Get() if err != nil { log.Infof("shutdown node %s: %s", context.Addr, err) } else { log.Infof("shutdown node in anticipation of data extermination: %s", body) } // Exterminate all data held in specified stores. for _, e := range context.Engines { if rocksdb, ok := e.(*engine.RocksDB); ok { log.Infof("exterminating data from store %s", e) if err := rocksdb.Destroy(); err != nil { log.Errorf("unable to destroy store %s: %s", e, err) osExit(1) } } } log.Infof("exterminated all data from stores %s", context.Engines) }
// runQuit accesses the quit shutdown path. func runQuit(cmd *cobra.Command, args []string) { admin := client.NewAdminClient(&context.Context, context.Addr, client.Quit) body, err := admin.Get() if err != nil { fmt.Printf("shutdown node error: %s\n", err) osExit(1) return } fmt.Printf("node drained and shutdown: %s\n", body) }
// runRmZone invokes the REST API with DELETE action and key prefix as // path. func runRmZone(cmd *cobra.Command, args []string) { if len(args) != 1 { cmd.Usage() return } admin := client.NewAdminClient(&Context.Context, Context.Addr, client.Zone) if err := admin.Delete(args[0]); err != nil { log.Error(err) return } fmt.Printf("Deleted zone key %q\n", args[0]) }
// runRmPerms invokes the REST API with DELETE action and key prefix as // path. func runRmPerms(cmd *cobra.Command, args []string) { if len(args) != 1 { cmd.Usage() return } admin := client.NewAdminClient(&context.Context, context.Addr, client.Permission) if err := admin.Delete(args[0]); err != nil { log.Error(err) return } fmt.Printf("Deleted permission key %q\n", args[0]) }
// runLsAccts invokes the REST API with GET action and no path, which // fetches a list of all acct configuration prefixes. func runLsAccts(cmd *cobra.Command, args []string) { if len(args) > 0 { cmd.Usage() return } admin := client.NewAdminClient(&Context.Context, Context.Addr, client.Accounting) list, err := admin.List() if err != nil { log.Error(err) return } fmt.Printf("Accounting keys:\n%s\n", strings.Join(list, "\n ")) }
// runGetAcct invokes the REST API with GET action and key prefix as path. func runGetAcct(cmd *cobra.Command, args []string) { if len(args) != 1 { cmd.Usage() return } admin := client.NewAdminClient(&Context.Context, Context.Addr, client.Accounting) body, err := admin.GetYAML(args[0]) if err != nil { log.Error(err) return } fmt.Printf("Accounting config for prefix %q:\n%s\n", args[0], body) }
// runSetAcct invokes the REST API with POST action and key prefix as // path. The specified configuration file is read from disk and sent // as the POST body. func runSetAcct(cmd *cobra.Command, args []string) { if len(args) != 2 { cmd.Usage() return } // Read in the config file. body, err := ioutil.ReadFile(args[1]) if err != nil { log.Errorf("unable to read accounting config file %q: %s", args[1], err) return } admin := client.NewAdminClient(&Context.Context, Context.Addr, client.Accounting) if err := admin.SetYAML(args[0], string(body)); err != nil { log.Error(err) return } fmt.Printf("Wrote accounting config to %q\n", args[0]) }
// Example_zone shows how to use the admin client to // get/set/list/delete zone configs. func Example_zone() { s := server.StartTestServer(nil) defer s.Stop() context := testutils.NewRootTestBaseContext() client := client.NewAdminClient(context, s.ServingAddr(), client.Zone) const yamlConfig = ` replicas: - attrs: [dc1, ssd] - attrs: [dc2, ssd] - attrs: [dc3, ssd] range_min_bytes: 1048576 range_max_bytes: 67108864 ` const jsonConfig = `{ "replica_attrs": [ { "attrs": [ "dc1", "ssd" ] }, { "attrs": [ "dc2", "ssd" ] }, { "attrs": [ "dc3", "ssd" ] } ], "range_min_bytes": 1048576, "range_max_bytes": 67108864 }` testData := []struct { prefix proto.Key cfg string isJSON bool }{ {proto.KeyMin, yamlConfig, false}, {proto.Key("db1"), yamlConfig, false}, {proto.Key("db 2"), jsonConfig, true}, {proto.Key("\xfe"), jsonConfig, true}, } // Write configs. for _, test := range testData { prefix := string(test.prefix) if test.isJSON { fmt.Printf("Set JSON zone config for %q\n", prefix) if err := client.SetJSON(prefix, test.cfg); err != nil { log.Fatal(err) } } else { fmt.Printf("Set YAML zone config for %q\n", prefix) if err := client.SetYAML(prefix, test.cfg); err != nil { log.Fatal(err) } } } // Get configs in various format. body, err := client.GetJSON("db1") if err != nil { log.Fatal(err) } fmt.Printf("JSON config for \"db1\":\n%s\n", body) body, err = client.GetYAML("db 2") if err != nil { log.Fatal(err) } fmt.Printf("YAML config for \"db 2\":\n%s\n", body) // List keys. keys, err := client.List() if err != nil { log.Fatal(err) } fmt.Printf("Zone prefixes: %q\n", keys) // Remove keys: the default one cannot be removed. err = client.Delete("") if err == nil { log.Fatal("expected error") } err = client.Delete("db 2") if err != nil { log.Fatal(err) } // List keys again. keys, err = client.List() if err != nil { log.Fatal(err) } fmt.Printf("Zone prefixes: %q\n", keys) // Output: // Set YAML zone config for "" // Set YAML zone config for "db1" // Set JSON zone config for "db 2" // Set JSON zone config for "\xfe" // JSON config for "db1": // { // "replica_attrs": [ // { // "attrs": [ // "dc1", // "ssd" // ] // }, // { // "attrs": [ // "dc2", // "ssd" // ] // }, // { // "attrs": [ // "dc3", // "ssd" // ] // } // ], // "range_min_bytes": 1048576, // "range_max_bytes": 67108864 // } // YAML config for "db 2": // replicas: // - attrs: [dc1, ssd] // - attrs: [dc2, ssd] // - attrs: [dc3, ssd] // range_min_bytes: 1048576 // range_max_bytes: 67108864 // // Zone prefixes: ["" "db 2" "db1" "\xfe"] // Zone prefixes: ["" "db1" "\xfe"] }
// Example_accounting shows how to use the admin client to // get/set/list/delete accounting configs. func Example_accounting() { s := server.StartTestServer(nil) defer s.Stop() context := testutils.NewRootTestBaseContext() client := client.NewAdminClient(context, s.ServingAddr(), client.Accounting) const yamlConfig = `cluster_id: test` const jsonConfig = `{ "cluster_id": "test" }` testData := []struct { prefix proto.Key cfg string isJSON bool }{ {proto.KeyMin, yamlConfig, false}, {proto.Key("db1"), yamlConfig, false}, {proto.Key("db 2"), jsonConfig, true}, {proto.Key("\xfe"), jsonConfig, true}, } // Write configs. for _, test := range testData { prefix := string(test.prefix) if test.isJSON { fmt.Printf("Set JSON accounting config for %q\n", prefix) if err := client.SetJSON(prefix, test.cfg); err != nil { log.Fatal(err) } } else { fmt.Printf("Set YAML accounting config for %q\n", prefix) if err := client.SetYAML(prefix, test.cfg); err != nil { log.Fatal(err) } } } // Get configs in various format. body, err := client.GetJSON("db1") if err != nil { log.Fatal(err) } fmt.Printf("JSON config for \"db1\":\n%s\n", body) body, err = client.GetYAML("db 2") if err != nil { log.Fatal(err) } fmt.Printf("YAML config for \"db 2\":\n%s\n", body) // List keys. keys, err := client.List() if err != nil { log.Fatal(err) } fmt.Printf("Accounting prefixes: %q\n", keys) // Remove keys: the default one cannot be removed. err = client.Delete("") if err == nil { log.Fatal("expected error") } err = client.Delete("db 2") if err != nil { log.Fatal(err) } // List keys again. keys, err = client.List() if err != nil { log.Fatal(err) } fmt.Printf("Accounting prefixes: %q\n", keys) // Output: // Set YAML accounting config for "" // Set YAML accounting config for "db1" // Set JSON accounting config for "db 2" // Set JSON accounting config for "\xfe" // JSON config for "db1": // { // "cluster_id": "test" // } // YAML config for "db 2": // cluster_id: test // // Accounting prefixes: ["" "db 2" "db1" "\xfe"] // Accounting prefixes: ["" "db1" "\xfe"] }
// Example_user shows how to use the admin client to // get/set/list/delete user configs. func Example_user() { s := server.StartTestServer(nil) defer s.Stop() context := testutils.NewRootTestBaseContext() client := client.NewAdminClient(context, s.ServingAddr(), client.User) const yamlConfig = `hashed_password: - 10 - 20` const jsonConfig = `{ "hashed_password": "******" }` testData := []struct { prefix proto.Key cfg string isJSON bool }{ {proto.Key("db1"), yamlConfig, false}, {proto.Key("db 2"), jsonConfig, true}, {proto.Key("\xfe"), jsonConfig, true}, } // Overwriting the default entry fails. err := client.SetYAML("", yamlConfig) if err == nil { log.Fatal("expected error") } // Write configs. for _, test := range testData { prefix := string(test.prefix) if test.isJSON { fmt.Printf("Set JSON user config for %q\n", prefix) if err := client.SetJSON(prefix, test.cfg); err != nil { log.Fatal(err) } } else { fmt.Printf("Set YAML user config for %q\n", prefix) if err := client.SetYAML(prefix, test.cfg); err != nil { log.Fatal(err) } } } // Get configs in various format. body, err := client.GetJSON("db1") if err != nil { log.Fatal(err) } fmt.Printf("JSON config for \"db1\":\n%s\n", body) body, err = client.GetYAML("db 2") if err != nil { log.Fatal(err) } fmt.Printf("YAML config for \"db 2\":\n%s\n", body) // List keys. keys, err := client.List() if err != nil { log.Fatal(err) } fmt.Printf("Users: %q\n", keys) // Remove keys: the default one cannot be removed. err = client.Delete("") if err == nil { log.Fatal("expected error") } err = client.Delete("db 2") if err != nil { log.Fatal(err) } // List keys again. keys, err = client.List() if err != nil { log.Fatal(err) } fmt.Printf("Users: %q\n", keys) // Output: // Set YAML user config for "db1" // Set JSON user config for "db 2" // Set JSON user config for "\xfe" // JSON config for "db1": // { // "hashed_password": "******" // } // YAML config for "db 2": // hashed_password: // - 10 // - 20 // // Users: ["" "db 2" "db1" "\xfe"] // Users: ["" "db1" "\xfe"] }
// Example_permission shows how to use the admin client to // get/set/list/delete permission configs. func Example_permission() { s := server.StartTestServer(nil) defer s.Stop() context := testutils.NewRootTestBaseContext() client := client.NewAdminClient(context, s.ServingAddr(), client.Permission) // The test server creates a permission config entry for 'server.TestUser'. // Delete it first so it does not interfere with our configs. err := client.Delete(server.TestUser) if err != nil { log.Fatal(err) } const yamlConfig = ` read: [readonly, readwrite] write: [readwrite, writeonly] ` const jsonConfig = `{ "read": [ "readonly", "readwrite" ], "write": [ "readwrite", "writeonly" ] }` testData := []struct { prefix proto.Key cfg string isJSON bool }{ {proto.KeyMin, yamlConfig, false}, {proto.Key("db1"), yamlConfig, false}, {proto.Key("db 2"), jsonConfig, true}, {proto.Key("\xfe"), jsonConfig, true}, } // Write configs. for _, test := range testData { prefix := string(test.prefix) if test.isJSON { fmt.Printf("Set JSON permission config for %q\n", prefix) if err := client.SetJSON(prefix, test.cfg); err != nil { log.Fatal(err) } } else { fmt.Printf("Set YAML permission config for %q\n", prefix) if err := client.SetYAML(prefix, test.cfg); err != nil { log.Fatal(err) } } } // Get configs in various format. body, err := client.GetJSON("db1") if err != nil { log.Fatal(err) } fmt.Printf("JSON config for \"db1\":\n%s\n", body) body, err = client.GetYAML("db 2") if err != nil { log.Fatal(err) } fmt.Printf("YAML config for \"db 2\":\n%s\n", body) // List keys. keys, err := client.List() if err != nil { log.Fatal(err) } fmt.Printf("Permission prefixes: %q\n", keys) // Remove keys: the default one cannot be removed. err = client.Delete("") if err == nil { log.Fatal("expected error") } err = client.Delete("db 2") if err != nil { log.Fatal(err) } // List keys again. keys, err = client.List() if err != nil { log.Fatal(err) } fmt.Printf("Permission prefixes: %q\n", keys) // Output: // Set YAML permission config for "" // Set YAML permission config for "db1" // Set JSON permission config for "db 2" // Set JSON permission config for "\xfe" // JSON config for "db1": // { // "read": [ // "readonly", // "readwrite" // ], // "write": [ // "readwrite", // "writeonly" // ] // } // YAML config for "db 2": // read: // - readonly // - readwrite // write: // - readwrite // - writeonly // // Permission prefixes: ["" "db 2" "db1" "\xfe"] // Permission prefixes: ["" "db1" "\xfe"] }