diff --git a/src/common/prop.c b/src/common/prop.c index f581bc7425a..cdbe4dd1b7f 100644 --- a/src/common/prop.c +++ b/src/common/prop.c @@ -1,6 +1,6 @@ /** * (C) Copyright 2019-2023 Intel Corporation. - * (C) Copyright 2025 Hewlett Packard Enterprise Development LP + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -77,6 +77,18 @@ daos_prop_has_ptr(struct daos_prop_entry *entry) return false; } +bool +daos_prop_has_byteval(struct daos_prop_entry *entry) +{ + switch (entry->dpe_type) { + /* + * e.g. DAOS_PROP_PO_POOL_CA (DAOS-18783) + */ + default: + return false; + } +} + static void daos_prop_entry_free_value(struct daos_prop_entry *entry) { @@ -93,6 +105,16 @@ daos_prop_entry_free_value(struct daos_prop_entry *entry) return; } + if (daos_prop_has_byteval(entry)) { + struct daos_prop_byteval *bv = entry->dpe_val_ptr; + + if (bv != NULL) { + D_FREE(bv->dpb_data); + D_FREE(entry->dpe_val_ptr); + } + return; + } + if (daos_prop_has_ptr(entry)) { D_FREE(entry->dpe_val_ptr); return; @@ -592,6 +614,10 @@ daos_prop_entry_copy(struct daos_prop_entry *entry, entry_dup->dpe_type = entry->dpe_type; entry_dup->dpe_flags = entry->dpe_flags; + + if (daos_prop_has_byteval(entry)) + return daos_prop_entry_dup_byteval(entry_dup, entry); + switch (entry->dpe_type) { case DAOS_PROP_PO_LABEL: case DAOS_PROP_CO_LABEL: @@ -751,6 +777,53 @@ daos_prop_set_ptr(daos_prop_t *prop, uint32_t type, const void *ptr, daos_size_t return daos_prop_entry_set_ptr(entry, ptr, size); } +int +daos_prop_set_byteval(daos_prop_t *prop, uint32_t type, const void *data, size_t len) +{ + struct daos_prop_entry *entry; + + entry = daos_prop_entry_get(prop, type); + if (entry == NULL) + return -DER_NONEXIST; + + return daos_prop_entry_set_byteval(entry, data, len); +} + +int +daos_prop_entry_set_byteval(struct daos_prop_entry *entry, const void *data, size_t len) +{ + struct daos_prop_byteval *bv; + + if (entry == NULL) + return -DER_INVAL; + if (!daos_prop_has_byteval(entry)) { + D_ERROR("Entry type %d does not expect a byteval\n", entry->dpe_type); + return -DER_INVAL; + } + + if (entry->dpe_val_ptr != NULL) { + bv = entry->dpe_val_ptr; + D_FREE(bv->dpb_data); + D_FREE(entry->dpe_val_ptr); + } + + if (data == NULL || len == 0) + return 0; + + D_ALLOC_PTR(bv); + if (bv == NULL) + return -DER_NOMEM; + D_ALLOC(bv->dpb_data, len); + if (bv->dpb_data == NULL) { + D_FREE(bv); + return -DER_NOMEM; + } + memcpy(bv->dpb_data, data, len); + bv->dpb_len = len; + entry->dpe_val_ptr = bv; + return 0; +} + int daos_prop_entry_set_ptr(struct daos_prop_entry *entry, const void *ptr, daos_size_t size) { @@ -966,6 +1039,23 @@ daos_prop_entry_dup_ptr(struct daos_prop_entry *entry_dst, return 0; } +int +daos_prop_entry_dup_byteval(struct daos_prop_entry *entry_dst, struct daos_prop_entry *entry_src) +{ + struct daos_prop_byteval *src_bv; + + D_ASSERT(entry_src != NULL); + D_ASSERT(entry_dst != NULL); + + src_bv = entry_src->dpe_val_ptr; + if (src_bv == NULL || src_bv->dpb_data == NULL || src_bv->dpb_len == 0) { + entry_dst->dpe_val_ptr = NULL; + return 0; + } + + return daos_prop_entry_set_byteval(entry_dst, src_bv->dpb_data, src_bv->dpb_len); +} + int daos_prop_entry_cmp_acl(struct daos_prop_entry *entry1, struct daos_prop_entry *entry2) diff --git a/src/control/common/proto/mgmt/addons.go b/src/control/common/proto/mgmt/addons.go index e07f43c5918..688f80c36a6 100644 --- a/src/control/common/proto/mgmt/addons.go +++ b/src/control/common/proto/mgmt/addons.go @@ -1,6 +1,6 @@ // // (C) Copyright 2019-2024 Intel Corporation. -// (C) Copyright 2025 Hewlett Packard Enterprise Development LP +// (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP // // SPDX-License-Identifier: BSD-2-Clause-Patent // @@ -8,6 +8,7 @@ package mgmt import ( + "encoding/base64" "encoding/json" "fmt" @@ -18,8 +19,9 @@ func (p *PoolProperty) UnmarshalJSON(b []byte) error { type fromJSON PoolProperty from := struct { Value struct { - Strval string `json:"strval"` - Numval uint64 `json:"numval"` + Strval string `json:"strval"` + Numval uint64 `json:"numval"` + Byteval string `json:"byteval"` } *fromJSON }{ @@ -30,7 +32,13 @@ func (p *PoolProperty) UnmarshalJSON(b []byte) error { return err } - if from.Value.Strval != "" { + if from.Value.Byteval != "" { + decoded, err := base64.StdEncoding.DecodeString(from.Value.Byteval) + if err != nil { + return err + } + p.SetValueBytes(decoded) + } else if from.Value.Strval != "" { p.SetValueString(from.Value.Strval) } else { p.SetValueNumber(from.Value.Numval) @@ -53,6 +61,13 @@ func (p *PoolProperty) SetValueNumber(numVal uint64) { } } +// SetValueBytes sets the Value field to a byte array. +func (p *PoolProperty) SetValueBytes(byteVal []byte) { + p.Value = &PoolProperty_Byteval{ + Byteval: byteVal, + } +} + // The following set of addons implements the poolServiceReq interface // in mgmt_pool.go. diff --git a/src/control/common/proto/mgmt/addons_test.go b/src/control/common/proto/mgmt/addons_test.go new file mode 100644 index 00000000000..28a5efef7cf --- /dev/null +++ b/src/control/common/proto/mgmt/addons_test.go @@ -0,0 +1,67 @@ +// +// (C) Copyright 2026 Hewlett Packard Enterprise Development LP +// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// + +package mgmt + +import ( + "encoding/json" + "testing" + + "github.com/google/go-cmp/cmp" + "google.golang.org/protobuf/testing/protocmp" +) + +func TestPoolProperty_SetValueBytes(t *testing.T) { + p := &PoolProperty{Number: 1} + data := []byte("test-cert-data") + + p.SetValueBytes(data) + + got := p.GetByteval() + if diff := cmp.Diff(data, got); diff != "" { + t.Fatalf("unexpected byteval (-want, +got):\n%s\n", diff) + } +} + +func TestPoolProperty_UnmarshalJSON(t *testing.T) { + for name, tc := range map[string]struct { + input string + exp *PoolProperty + }{ + "string value": { + input: `{"number": 1, "value": {"strval": "hello"}}`, + exp: &PoolProperty{ + Number: 1, + Value: &PoolProperty_Strval{Strval: "hello"}, + }, + }, + "number value": { + input: `{"number": 2, "value": {"numval": 42}}`, + exp: &PoolProperty{ + Number: 2, + Value: &PoolProperty_Numval{Numval: 42}, + }, + }, + "byte value": { + // "dGVzdC1jZXJ0LWRhdGE=" is base64 for "test-cert-data" + input: `{"number": 3, "value": {"byteval": "dGVzdC1jZXJ0LWRhdGE="}}`, + exp: &PoolProperty{ + Number: 3, + Value: &PoolProperty_Byteval{Byteval: []byte("test-cert-data")}, + }, + }, + } { + t.Run(name, func(t *testing.T) { + got := &PoolProperty{} + if err := json.Unmarshal([]byte(tc.input), got); err != nil { + t.Fatalf("unexpected error: %s", err) + } + if diff := cmp.Diff(tc.exp, got, protocmp.Transform()); diff != "" { + t.Fatalf("unexpected result (-want, +got):\n%s\n", diff) + } + }) + } +} diff --git a/src/control/common/proto/mgmt/pool.pb.go b/src/control/common/proto/mgmt/pool.pb.go index 12286b528fb..d3c3dacaebc 100644 --- a/src/control/common/proto/mgmt/pool.pb.go +++ b/src/control/common/proto/mgmt/pool.pb.go @@ -2066,6 +2066,7 @@ type PoolProperty struct { // // *PoolProperty_Strval // *PoolProperty_Numval + // *PoolProperty_Byteval Value isPoolProperty_Value `protobuf_oneof:"value"` } @@ -2129,6 +2130,13 @@ func (x *PoolProperty) GetNumval() uint64 { return 0 } +func (x *PoolProperty) GetByteval() []byte { + if x, ok := x.GetValue().(*PoolProperty_Byteval); ok { + return x.Byteval + } + return nil +} + type isPoolProperty_Value interface { isPoolProperty_Value() } @@ -2141,10 +2149,16 @@ type PoolProperty_Numval struct { Numval uint64 `protobuf:"varint,3,opt,name=numval,proto3,oneof"` // pool property numeric value } +type PoolProperty_Byteval struct { + Byteval []byte `protobuf:"bytes,4,opt,name=byteval,proto3,oneof"` // pool property byte array value +} + func (*PoolProperty_Strval) isPoolProperty_Value() {} func (*PoolProperty_Numval) isPoolProperty_Value() {} +func (*PoolProperty_Byteval) isPoolProperty_Value() {} + // PoolSetPropReq represents a request to set pool properties. type PoolSetPropReq struct { state protoimpl.MessageState @@ -3323,117 +3337,119 @@ var file_mgmt_pool_proto_rawDesc = []byte{ 0x6c, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x73, 0x79, 0x73, 0x53, 0x65, 0x6c, 0x66, 0x48, 0x65, 0x61, 0x6c, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6e, - 0x6f, 0x64, 0x65, 0x73, 0x22, 0x63, 0x0a, 0x0c, 0x50, 0x6f, 0x6f, 0x6c, 0x50, 0x72, 0x6f, 0x70, + 0x6f, 0x64, 0x65, 0x73, 0x22, 0x7f, 0x0a, 0x0c, 0x50, 0x6f, 0x6f, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x18, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x48, 0x00, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x76, 0x61, 0x6c, - 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x83, 0x01, 0x0a, 0x0e, 0x50, 0x6f, - 0x6f, 0x6c, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, - 0x73, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x32, - 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x50, 0x6f, 0x6f, 0x6c, 0x50, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, - 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, 0x22, - 0x29, 0x0a, 0x0f, 0x50, 0x6f, 0x6f, 0x6c, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x52, 0x65, - 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x83, 0x01, 0x0a, 0x0e, 0x50, - 0x6f, 0x6f, 0x6c, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, - 0x03, 0x73, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x32, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x50, 0x6f, 0x6f, 0x6c, 0x50, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, - 0x69, 0x65, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, - 0x22, 0x5d, 0x0a, 0x0f, 0x50, 0x6f, 0x6f, 0x6c, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x52, - 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x32, 0x0a, 0x0a, 0x70, - 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x12, 0x1a, 0x0a, 0x07, 0x62, 0x79, 0x74, 0x65, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0c, 0x48, 0x00, 0x52, 0x07, 0x62, 0x79, 0x74, 0x65, 0x76, 0x61, 0x6c, 0x42, 0x07, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x83, 0x01, 0x0a, 0x0e, 0x50, 0x6f, 0x6f, 0x6c, 0x53, 0x65, + 0x74, 0x50, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x32, 0x0a, 0x0a, 0x70, 0x72, + 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, + 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x50, 0x6f, 0x6f, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, + 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, 0x1b, + 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, 0x22, 0x29, 0x0a, 0x0f, 0x50, + 0x6f, 0x6f, 0x6c, 0x53, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x83, 0x01, 0x0a, 0x0e, 0x50, 0x6f, 0x6f, 0x6c, 0x47, + 0x65, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x32, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x50, 0x6f, 0x6f, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, - 0x72, 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, - 0x4f, 0x0a, 0x0e, 0x50, 0x6f, 0x6f, 0x6c, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, - 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, - 0x22, 0x81, 0x01, 0x0a, 0x12, 0x50, 0x6f, 0x6f, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x61, 0x6e, - 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x72, 0x61, 0x6e, 0x6b, 0x12, 0x18, 0x0a, - 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x07, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, - 0x61, 0x6e, 0x6b, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, - 0x61, 0x6e, 0x6b, 0x73, 0x22, 0x75, 0x0a, 0x12, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, - 0x66, 0x72, 0x65, 0x65, 0x12, 0x35, 0x0a, 0x0a, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, - 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x09, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x22, 0xb8, 0x02, 0x0a, 0x13, - 0x50, 0x6f, 0x6f, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x3b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x50, 0x6f, 0x6f, 0x6c, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x12, 0x2e, 0x0a, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x18, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x65, 0x6d, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, - 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x46, 0x69, 0x6c, - 0x65, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x27, 0x0a, 0x10, 0x6d, 0x64, 0x5f, 0x6f, 0x6e, 0x5f, - 0x73, 0x73, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0d, 0x6d, 0x64, 0x4f, 0x6e, 0x53, 0x73, 0x64, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, - 0x5f, 0x0a, 0x0b, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x11, - 0x0a, 0x0d, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, - 0x08, 0x0a, 0x04, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x12, 0x06, 0x0a, 0x02, 0x55, 0x50, 0x10, - 0x03, 0x12, 0x09, 0x0a, 0x05, 0x55, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, - 0x4e, 0x45, 0x57, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x52, 0x41, 0x49, 0x4e, 0x10, 0x06, - 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x5e, 0x0a, 0x13, 0x50, 0x6f, 0x6f, 0x6c, 0x51, 0x75, - 0x65, 0x72, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x50, 0x6f, 0x6f, 0x6c, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x22, 0x54, 0x0a, 0x13, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, - 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, + 0x72, 0x74, 0x79, 0x52, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x12, + 0x1b, 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, 0x22, 0x5d, 0x0a, 0x0f, + 0x50, 0x6f, 0x6f, 0x6c, 0x47, 0x65, 0x74, 0x50, 0x72, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x70, 0x12, + 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x32, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, + 0x72, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x67, + 0x6d, 0x74, 0x2e, 0x50, 0x6f, 0x6f, 0x6c, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x52, + 0x0a, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x0e, 0x50, + 0x6f, 0x6f, 0x6c, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, 0x22, 0x69, 0x0a, 0x12, - 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x6f, 0x70, 0x52, - 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x76, - 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x73, - 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, 0x22, 0x76, 0x0a, 0x13, 0x50, 0x6f, 0x6f, 0x6c, 0x53, - 0x65, 0x6c, 0x66, 0x48, 0x65, 0x61, 0x6c, 0x45, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x10, + 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, 0x22, 0x81, 0x01, 0x0a, + 0x12, 0x50, 0x6f, 0x6f, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x61, 0x6e, 0x6b, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x04, 0x72, 0x61, 0x6e, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, + 0x22, 0x75, 0x0a, 0x12, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x12, 0x0a, 0x04, + 0x66, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x66, 0x72, 0x65, 0x65, + 0x12, 0x35, 0x0a, 0x0a, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x53, 0x74, 0x6f, 0x72, + 0x61, 0x67, 0x65, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x52, 0x09, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x22, 0xb8, 0x02, 0x0a, 0x13, 0x50, 0x6f, 0x6f, 0x6c, + 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x3b, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, + 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x50, 0x6f, 0x6f, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x05, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6d, 0x67, + 0x6d, 0x74, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x05, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x24, 0x0a, 0x0e, + 0x6d, 0x65, 0x6d, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x46, 0x69, 0x6c, 0x65, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x12, 0x27, 0x0a, 0x10, 0x6d, 0x64, 0x5f, 0x6f, 0x6e, 0x5f, 0x73, 0x73, 0x64, 0x5f, + 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0d, 0x6d, 0x64, + 0x4f, 0x6e, 0x53, 0x73, 0x64, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x22, 0x5f, 0x0a, 0x0b, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0c, 0x0a, + 0x08, 0x44, 0x4f, 0x57, 0x4e, 0x5f, 0x4f, 0x55, 0x54, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x44, + 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x12, 0x06, 0x0a, 0x02, 0x55, 0x50, 0x10, 0x03, 0x12, 0x09, 0x0a, + 0x05, 0x55, 0x50, 0x5f, 0x49, 0x4e, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x4e, 0x45, 0x57, 0x10, + 0x05, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x52, 0x41, 0x49, 0x4e, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x01, + 0x10, 0x02, 0x22, 0x5e, 0x0a, 0x13, 0x50, 0x6f, 0x6f, 0x6c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x2f, 0x0a, 0x05, 0x69, 0x6e, 0x66, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x6d, 0x67, 0x6d, 0x74, 0x2e, 0x50, 0x6f, 0x6f, 0x6c, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x69, 0x6e, 0x66, + 0x6f, 0x73, 0x22, 0x54, 0x0a, 0x13, 0x50, 0x6f, 0x6f, 0x6c, 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, + 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, + 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, 0x22, 0x69, 0x0a, 0x12, 0x50, 0x6f, 0x6f, 0x6c, + 0x52, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x20, 0x0a, 0x0c, 0x73, 0x79, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x5f, 0x76, 0x61, 0x6c, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x50, 0x72, 0x6f, 0x70, 0x56, - 0x61, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, 0x2a, - 0x25, 0x0a, 0x10, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, - 0x79, 0x70, 0x65, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x43, 0x4d, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, - 0x4e, 0x56, 0x4d, 0x45, 0x10, 0x01, 0x2a, 0x5d, 0x0a, 0x10, 0x50, 0x6f, 0x6f, 0x6c, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x61, 0x64, - 0x79, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x69, 0x6e, - 0x67, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x45, 0x78, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, - 0x6f, 0x77, 0x6e, 0x10, 0x04, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x61, 0x6f, 0x73, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x64, - 0x61, 0x6f, 0x73, 0x2f, 0x73, 0x72, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2f, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x67, 0x6d, - 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x05, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, + 0x6e, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, + 0x6e, 0x6b, 0x73, 0x22, 0x76, 0x0a, 0x13, 0x50, 0x6f, 0x6f, 0x6c, 0x53, 0x65, 0x6c, 0x66, 0x48, + 0x65, 0x61, 0x6c, 0x45, 0x76, 0x61, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x79, + 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x79, 0x73, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0c, + 0x73, 0x79, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x70, 0x5f, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x50, 0x72, 0x6f, 0x70, 0x56, 0x61, 0x6c, 0x12, 0x1b, + 0x0a, 0x09, 0x73, 0x76, 0x63, 0x5f, 0x72, 0x61, 0x6e, 0x6b, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, + 0x0d, 0x52, 0x08, 0x73, 0x76, 0x63, 0x52, 0x61, 0x6e, 0x6b, 0x73, 0x2a, 0x25, 0x0a, 0x10, 0x53, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x4d, 0x65, 0x64, 0x69, 0x61, 0x54, 0x79, 0x70, 0x65, 0x12, + 0x07, 0x0a, 0x03, 0x53, 0x43, 0x4d, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x56, 0x4d, 0x45, + 0x10, 0x01, 0x2a, 0x5d, 0x0a, 0x10, 0x50, 0x6f, 0x6f, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x72, 0x65, 0x61, 0x74, 0x69, + 0x6e, 0x67, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x52, 0x65, 0x61, 0x64, 0x79, 0x10, 0x01, 0x12, + 0x0e, 0x0a, 0x0a, 0x44, 0x65, 0x73, 0x74, 0x72, 0x6f, 0x79, 0x69, 0x6e, 0x67, 0x10, 0x02, 0x12, + 0x13, 0x0a, 0x0f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x45, 0x78, 0x63, 0x6c, 0x75, 0x64, + 0x65, 0x64, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, + 0x04, 0x42, 0x3a, 0x5a, 0x38, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x64, 0x61, 0x6f, 0x73, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x64, 0x61, 0x6f, 0x73, 0x2f, + 0x73, 0x72, 0x63, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6d, 0x67, 0x6d, 0x74, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -3971,6 +3987,7 @@ func file_mgmt_pool_proto_init() { file_mgmt_pool_proto_msgTypes[22].OneofWrappers = []interface{}{ (*PoolProperty_Strval)(nil), (*PoolProperty_Numval)(nil), + (*PoolProperty_Byteval)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/src/control/lib/control/pool.go b/src/control/lib/control/pool.go index 6fd79c04af5..90206ffb80a 100644 --- a/src/control/lib/control/pool.go +++ b/src/control/lib/control/pool.go @@ -110,6 +110,14 @@ func convertPoolProps(in []*daos.PoolProperty, setProp bool) ([]*mgmtpb.PoolProp if err != nil { return nil, err } + if byteVal, err := prop.Value.GetBytes(); err == nil { + // Byte values bypass the string round-trip validation + // below because base64-encoding and re-parsing would + // fail for properties without a byte-aware handler. + out[i].SetValueBytes(byteVal) + continue + } + if setProp { if err := p.SetValue(prop.StringValue()); err != nil { return nil, err @@ -791,6 +799,8 @@ func PoolGetProp(ctx context.Context, rpcClient UnaryInvoker, req *PoolGetPropRe prop.Value.SetString(v.Strval) case *mgmtpb.PoolProperty_Numval: prop.Value.SetNumber(v.Numval) + case *mgmtpb.PoolProperty_Byteval: + prop.Value.SetBytes(v.Byteval) default: return nil, errors.Errorf("unable to represent response value %+v", v) } diff --git a/src/control/lib/control/pool_test.go b/src/control/lib/control/pool_test.go index 14f098b6a62..41abac179ce 100644 --- a/src/control/lib/control/pool_test.go +++ b/src/control/lib/control/pool_test.go @@ -2299,6 +2299,16 @@ func TestControl_PoolSetProp(t *testing.T) { }, }, }, + "success with byte value": { + req: &PoolSetPropReq{ + ID: test.MockUUID(), + Properties: func() []*daos.PoolProperty { + p := propWithVal("label", "ok") + p.Value.SetBytes([]byte("test-byte-data")) + return []*daos.PoolProperty{p} + }(), + }, + }, } { t.Run(name, func(t *testing.T) { log, buf := logging.NewTestLogger(t.Name()) @@ -2558,6 +2568,31 @@ func TestControl_PoolGetProp(t *testing.T) { propWithVal("space_rb", "42"), }, }, + "byte value in response": { + mic: &MockInvokerConfig{ + UnaryResponse: MockMSResponse("host1", nil, &mgmtpb.PoolGetPropResp{ + Properties: []*mgmtpb.PoolProperty{ + { + Number: propWithVal("label", "").Number, + Value: &mgmtpb.PoolProperty_Byteval{Byteval: []byte("test-cert-data")}, + }, + }, + }), + }, + req: &PoolGetPropReq{ + ID: test.MockUUID(), + Properties: []*daos.PoolProperty{ + propWithVal("label", ""), + }, + }, + expResp: []*daos.PoolProperty{ + func() *daos.PoolProperty { + p := propWithVal("label", "") + p.Value.SetBytes([]byte("test-cert-data")) + return p + }(), + }, + }, "missing props in response; compatibility with old pool": { mic: &MockInvokerConfig{ UnaryResponse: MockMSResponse("host1", nil, &mgmtpb.PoolGetPropResp{ diff --git a/src/control/lib/daos/pool_property.go b/src/control/lib/daos/pool_property.go index 59d642e1dba..dacebe794d4 100644 --- a/src/control/lib/daos/pool_property.go +++ b/src/control/lib/daos/pool_property.go @@ -9,6 +9,7 @@ package daos import ( + "encoding/base64" "encoding/json" "fmt" "math" @@ -757,6 +758,23 @@ func (ppv *PoolPropertyValue) SetNumber(numVal uint64) { ppv.data = numVal } +// SetBytes sets the property value to a byte array. +func (ppv *PoolPropertyValue) SetBytes(byteVal []byte) { + ppv.data = byteVal +} + +// GetBytes returns the byte array value set for the property, +// or an error if the value is not a byte array. +func (ppv *PoolPropertyValue) GetBytes() ([]byte, error) { + if !ppv.IsSet() { + return nil, errors.New("value not set") + } + if v, ok := ppv.data.([]byte); ok { + return v, nil + } + return nil, errors.Errorf("%+v is not []byte", ppv.data) +} + func (ppv *PoolPropertyValue) IsSet() bool { return ppv != nil && ppv.data != nil } @@ -771,6 +789,8 @@ func (ppv *PoolPropertyValue) String() string { return v case uint64: return strconv.FormatUint(v, 10) + case []byte: + return base64.StdEncoding.EncodeToString(v) default: return fmt.Sprintf("unknown data type for %+v", ppv.data) } diff --git a/src/control/lib/daos/pool_property_test.go b/src/control/lib/daos/pool_property_test.go index 52da5bfe140..f3efad04081 100644 --- a/src/control/lib/daos/pool_property_test.go +++ b/src/control/lib/daos/pool_property_test.go @@ -1,7 +1,7 @@ // // (C) Copyright 2021-2023 Intel Corporation. // (C) Copyright 2025 Google LLC -// (C) Copyright 2025 Hewlett Packard Enterprise Development LP +// (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP // // SPDX-License-Identifier: BSD-2-Clause-Patent // @@ -49,11 +49,13 @@ func TestDaos_PoolPropertyValue(t *testing.T) { } for name, tc := range map[string]struct { - val *daos.PoolPropertyValue - strVal *string - numVal *uint64 - expErr error - expStr string + val *daos.PoolPropertyValue + strVal *string + numVal *uint64 + byteVal []byte + expErr error + expStr string + expBytes []byte }{ "nil": { expErr: errors.New("not set"), @@ -75,11 +77,20 @@ func TestDaos_PoolPropertyValue(t *testing.T) { numVal: numPtr(42), expStr: "42", }, + "byte value": { + val: &daos.PoolPropertyValue{}, + byteVal: []byte("test-cert-data"), + expErr: errors.New("not uint64"), + expStr: "dGVzdC1jZXJ0LWRhdGE=", + expBytes: []byte("test-cert-data"), + }, } { t.Run(name, func(t *testing.T) { v := tc.val - if tc.strVal != nil { + if tc.byteVal != nil { + v.SetBytes(tc.byteVal) + } else if tc.strVal != nil { v.SetString(*tc.strVal) } else if tc.numVal != nil { v.SetNumber(*tc.numVal) @@ -90,6 +101,16 @@ func TestDaos_PoolPropertyValue(t *testing.T) { t.Fatalf("unexpected String() result (-want, +got):\n%s\n", diff) } + if tc.expBytes != nil { + gotBytes, err := v.GetBytes() + if err != nil { + t.Fatalf("unexpected GetBytes() error: %s", err) + } + if diff := cmp.Diff(tc.expBytes, gotBytes); diff != "" { + t.Fatalf("unexpected GetBytes() result (-want, +got):\n%s\n", diff) + } + } + gotNum, gotErr := v.GetNumber() test.CmpErr(t, tc.expErr, gotErr) if tc.expErr != nil { diff --git a/src/include/daos_prop.h b/src/include/daos_prop.h index d41c59bc50b..cdbada88dab 100644 --- a/src/include/daos_prop.h +++ b/src/include/daos_prop.h @@ -1,6 +1,6 @@ /** * (C) Copyright 2015-2023 Intel Corporation. - * (C) Copyright 2025 Hewlett Packard Enterprise Development LP + * (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP * * SPDX-License-Identifier: BSD-2-Clause-Patent */ @@ -145,6 +145,14 @@ enum daos_pool_props { #define DAOS_PROP_PO_NUM (DAOS_PROP_PO_MAX - DAOS_PROP_PO_MIN - 1) +/** Opaque byte-array value for properties. */ +struct daos_prop_byteval { + /** Property data */ + void *dpb_data; + /** Length of data */ + size_t dpb_len; +}; + #define DAOS_PROP_PO_EC_CELL_SZ_MIN (1UL << 10) #define DAOS_PROP_PO_EC_CELL_SZ_MAX (1UL << 30) @@ -799,6 +807,57 @@ int daos_prop_entry_dup_ptr(struct daos_prop_entry *entry_dst, struct daos_prop_entry *entry_src, size_t len); +/** + * Set the byte-array value of a named property in a property list. The + * property type must expect a byteval value (see daos_prop_has_byteval()). + * The buffer is duplicated internally and freed by daos_prop_free(); the + * caller does not need to retain \a data. If the entry already has a value + * set, it is freed before the new value is stored. + * + * \param[in,out] prop Property list + * \param[in] type Type of property to look for + * \param[in] data Bytes to copy into the entry. May be + * NULL when \a len is 0. + * \param[in] len Length of \a data in bytes. + * + * \return 0 Success + * -DER_INVAL Type does not expect a byteval + * -DER_NONEXIST No entry of \a type in \a prop + * -DER_NOMEM Out of memory + */ +int +daos_prop_set_byteval(daos_prop_t *prop, uint32_t type, const void *data, size_t len); + +/** + * Set the byte-array value of a property entry. As with daos_prop_set_byteval(), + * the buffer is duplicated internally and freed by daos_prop_free(). + * + * \param[in,out] entry Entry whose value to set. + * \param[in] data Bytes to copy into the entry. May be + * NULL when \a len is 0. + * \param[in] len Length of \a data in bytes. + * + * \return 0 Success + * -DER_INVAL Type does not expect a byteval + * -DER_NOMEM Out of memory + */ +int +daos_prop_entry_set_byteval(struct daos_prop_entry *entry, const void *data, size_t len); + +/** + * Duplicate a byte-array value from one DAOS prop entry to another. + * Convenience function. + * + * \param[in,out] entry_dst Destination entry + * \param[in] entry_src Source entry whose dpe_val_ptr owns + * a struct daos_prop_byteval. + * + * \return 0 Success + * -DER_NOMEM Out of memory + */ +int +daos_prop_entry_dup_byteval(struct daos_prop_entry *entry_dst, struct daos_prop_entry *entry_src); + /** * Compare a pair of daos_prop_entry that contain ACLs. * @@ -848,6 +907,19 @@ daos_prop_has_str(struct daos_prop_entry *entry); bool daos_prop_has_ptr(struct daos_prop_entry *entry); +/** + * Check a DAOS prop entry for an opaque byte-array value. When true, + * dpe_val_ptr is expected to point at a struct daos_prop_byteval owned + * by the daos_prop_t. + * + * \param[in] entry Entry to be checked. + * + * \return true Has a byte-array value. + * false Does not have a byte-array value. + */ +bool +daos_prop_has_byteval(struct daos_prop_entry *entry); + /** * Check if a DAOS prop entry is set or not. * diff --git a/src/mgmt/pool.pb-c.c b/src/mgmt/pool.pb-c.c index 301e074e0d8..929df01b990 100644 --- a/src/mgmt/pool.pb-c.c +++ b/src/mgmt/pool.pb-c.c @@ -3806,7 +3806,7 @@ const ProtobufCMessageDescriptor mgmt__pool_query_resp__descriptor = (ProtobufCMessageInit) mgmt__pool_query_resp__init, NULL,NULL,NULL /* reserved[123] */ }; -static const ProtobufCFieldDescriptor mgmt__pool_property__field_descriptors[3] = +static const ProtobufCFieldDescriptor mgmt__pool_property__field_descriptors[4] = { { "number", @@ -3844,8 +3844,21 @@ static const ProtobufCFieldDescriptor mgmt__pool_property__field_descriptors[3] 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ 0,NULL,NULL /* reserved1,reserved2, etc */ }, + { + "byteval", + 4, + PROTOBUF_C_LABEL_NONE, + PROTOBUF_C_TYPE_BYTES, + offsetof(Mgmt__PoolProperty, value_case), + offsetof(Mgmt__PoolProperty, byteval), + NULL, + NULL, + 0 | PROTOBUF_C_FIELD_FLAG_ONEOF, /* flags */ + 0,NULL,NULL /* reserved1,reserved2, etc */ + }, }; static const unsigned mgmt__pool_property__field_indices_by_name[] = { + 3, /* field[3] = byteval */ 0, /* field[0] = number */ 2, /* field[2] = numval */ 1, /* field[1] = strval */ @@ -3853,7 +3866,7 @@ static const unsigned mgmt__pool_property__field_indices_by_name[] = { static const ProtobufCIntRange mgmt__pool_property__number_ranges[1 + 1] = { { 1, 0 }, - { 0, 3 } + { 0, 4 } }; const ProtobufCMessageDescriptor mgmt__pool_property__descriptor = { @@ -3863,7 +3876,7 @@ const ProtobufCMessageDescriptor mgmt__pool_property__descriptor = "Mgmt__PoolProperty", "mgmt", sizeof(Mgmt__PoolProperty), - 3, + 4, mgmt__pool_property__field_descriptors, mgmt__pool_property__field_indices_by_name, 1, mgmt__pool_property__number_ranges, diff --git a/src/mgmt/pool.pb-c.h b/src/mgmt/pool.pb-c.h index a8596043bd9..382c2d5e0f9 100644 --- a/src/mgmt/pool.pb-c.h +++ b/src/mgmt/pool.pb-c.h @@ -898,7 +898,8 @@ struct _Mgmt__PoolQueryResp typedef enum { MGMT__POOL_PROPERTY__VALUE__NOT_SET = 0, MGMT__POOL_PROPERTY__VALUE_STRVAL = 2, - MGMT__POOL_PROPERTY__VALUE_NUMVAL = 3 + MGMT__POOL_PROPERTY__VALUE_NUMVAL = 3, + MGMT__POOL_PROPERTY__VALUE_BYTEVAL = 4 PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(MGMT__POOL_PROPERTY__VALUE) } Mgmt__PoolProperty__ValueCase; @@ -919,6 +920,10 @@ struct _Mgmt__PoolProperty * pool property numeric value */ uint64_t numval; + /* + * pool property byte array value + */ + ProtobufCBinaryData byteval; }; }; #define MGMT__POOL_PROPERTY__INIT \ diff --git a/src/mgmt/srv_drpc.c b/src/mgmt/srv_drpc.c index 6145dadc998..e1cca1f9ea4 100644 --- a/src/mgmt/srv_drpc.c +++ b/src/mgmt/srv_drpc.c @@ -282,6 +282,12 @@ conv_req_props(daos_prop_t **out_prop, bool set_props, case MGMT__POOL_PROPERTY__VALUE_NUMVAL: entry->dpe_val = req_props[i]->numval; break; + case MGMT__POOL_PROPERTY__VALUE_BYTEVAL: + rc = daos_prop_entry_set_byteval(entry, req_props[i]->byteval.data, + req_props[i]->byteval.len); + if (rc != 0) + D_GOTO(out, rc); + break; default: D_ERROR("Pool property request with no value (%d)\n", req_props[i]->value_case); @@ -1149,6 +1155,8 @@ free_response_props(Mgmt__PoolProperty **props, size_t n_props) for (i = 0; i < n_props; i++) { if (props[i]->value_case == MGMT__POOL_PROPERTY__VALUE_STRVAL) D_FREE(props[i]->strval); + else if (props[i]->value_case == MGMT__POOL_PROPERTY__VALUE_BYTEVAL) + D_FREE(props[i]->byteval.data); D_FREE(props[i]); } diff --git a/src/mgmt/tests/srv_drpc_tests.c b/src/mgmt/tests/srv_drpc_tests.c index aac8c4351ed..89405711a6e 100644 --- a/src/mgmt/tests/srv_drpc_tests.c +++ b/src/mgmt/tests/srv_drpc_tests.c @@ -980,6 +980,37 @@ test_drpc_pool_set_prop_success(void **state) D_FREE(resp.body.data); } +/* + * TODO (DAOS-18783): Add happy-path byteval test with new property. + */ + +static void +test_drpc_pool_set_prop_byteval_invalid_type(void **state) +{ + Drpc__Call call = DRPC__CALL__INIT; + Drpc__Response resp = DRPC__RESPONSE__INIT; + Mgmt__PoolSetPropReq req = MGMT__POOL_SET_PROP_REQ__INIT; + uint8_t byte_data[] = {0x01, 0x02, 0x03, 0x04}; + + req.id = TEST_UUID; + req.properties = alloc_prop_msg_list(1); + req.n_properties = 1; + + req.properties[0]->number = DAOS_PROP_PO_MAX; + req.properties[0]->byteval.data = byte_data; + req.properties[0]->byteval.len = sizeof(byte_data); + req.properties[0]->value_case = MGMT__POOL_PROPERTY__VALUE_BYTEVAL; + setup_pool_set_prop_drpc_call(&call, &req); + + ds_mgmt_drpc_pool_set_prop(&call, &resp); + + expect_drpc_pool_set_prop_resp_with_error(&resp, -DER_INVAL); + + free_prop_msg_list(req.properties, req.n_properties); + D_FREE(call.body.data); + D_FREE(resp.body.data); +} + /* * dRPC Pool GetProp setup/teardown */ @@ -3450,6 +3481,7 @@ main(void) POOL_SET_PROP_TEST(test_drpc_pool_set_prop_invalid_value_type), POOL_SET_PROP_TEST(test_drpc_pool_set_prop_bad_uuid), POOL_SET_PROP_TEST(test_drpc_pool_set_prop_success), + POOL_SET_PROP_TEST(test_drpc_pool_set_prop_byteval_invalid_type), POOL_GET_PROP_TEST(test_drpc_pool_get_prop_bad_uuid), POOL_GET_PROP_TEST(test_drpc_pool_get_prop_num_success), POOL_GET_PROP_TEST(test_drpc_pool_get_prop_str_success), diff --git a/src/proto/mgmt/pool.proto b/src/proto/mgmt/pool.proto index 5fc7c8762c5..e994f979545 100644 --- a/src/proto/mgmt/pool.proto +++ b/src/proto/mgmt/pool.proto @@ -262,6 +262,7 @@ message PoolProperty { oneof value { string strval = 2; // pool property string value uint64 numval = 3; // pool property numeric value + bytes byteval = 4; // pool property byte array value } }