From f65c78c123c3728ced1dac82c96a8fc2577597d8 Mon Sep 17 00:00:00 2001 From: Piotr Piotrowski Date: Fri, 1 Sep 2023 11:24:40 +0200 Subject: [PATCH] [ADDED] Object store and object metadata Signed-off-by: Piotr Piotrowski --- object.go | 18 +++++++++++++++--- test/object_test.go | 29 ++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/object.go b/object.go index b02507260..ae96a2792 100644 --- a/object.go +++ b/object.go @@ -157,6 +157,10 @@ type ObjectStoreConfig struct { Storage StorageType `json:"storage,omitempty"` Replicas int `json:"num_replicas,omitempty"` Placement *Placement `json:"placement,omitempty"` + + // Bucket-specific metadata + // NOTE: Metadata requires nats-server v2.10.0+ + Metadata map[string]string `json:"metadata,omitempty"` } type ObjectStoreStatus interface { @@ -176,6 +180,8 @@ type ObjectStoreStatus interface { Size() uint64 // BackingStore provides details about the underlying storage BackingStore() string + // Metadata is the user supplied metadata for the bucket + Metadata() map[string]string } // ObjectMetaOptions @@ -186,9 +192,10 @@ type ObjectMetaOptions struct { // ObjectMeta is high level information about an object. type ObjectMeta struct { - Name string `json:"name"` - Description string `json:"description,omitempty"` - Headers Header `json:"headers,omitempty"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + Headers Header `json:"headers,omitempty"` + Metadata map[string]string `json:"metadata,omitempty"` // Optional options. Opts *ObjectMetaOptions `json:"options,omitempty"` @@ -280,6 +287,7 @@ func (js *js) CreateObjectStore(cfg *ObjectStoreConfig) (ObjectStore, error) { Discard: DiscardNew, AllowRollup: true, AllowDirect: true, + Metadata: cfg.Metadata, } // Create our stream. @@ -974,6 +982,7 @@ func (obs *obs) UpdateMeta(name string, meta *ObjectMeta) error { info.Name = meta.Name info.Description = meta.Description info.Headers = meta.Headers + info.Metadata = meta.Metadata // Prepare the meta message if err = publishMeta(info, obs.js); err != nil { @@ -1197,6 +1206,9 @@ func (s *ObjectBucketStatus) Size() uint64 { return s.nfo.State.Bytes } // BackingStore indicates what technology is used for storage of the bucket func (s *ObjectBucketStatus) BackingStore() string { return "JetStream" } +// Metadata is the metadata supplied when creating the bucket +func (s *ObjectBucketStatus) Metadata() map[string]string { return s.nfo.Config.Metadata } + // StreamInfo is the stream info retrieved to create the status func (s *ObjectBucketStatus) StreamInfo() *StreamInfo { return s.nfo } diff --git a/test/object_test.go b/test/object_test.go index 93e345eca..28b109028 100644 --- a/test/object_test.go +++ b/test/object_test.go @@ -401,27 +401,45 @@ func TestObjectMetadata(t *testing.T) { nc, js := jsClient(t, s) defer nc.Close() - obs, err := js.CreateObjectStore(&nats.ObjectStoreConfig{Bucket: "META-TEST"}) + bucketMetadata := map[string]string{"foo": "bar", "baz": "boo"} + obs, err := js.CreateObjectStore(&nats.ObjectStoreConfig{ + Bucket: "META-TEST", + Metadata: bucketMetadata, + }) + expectOk(t, err) + status, err := obs.Status() expectOk(t, err) + if !reflect.DeepEqual(status.Metadata(), bucketMetadata) { + t.Fatalf("invalid bucket metadata: %+v", status.Metadata()) + } // Simple with no Meta. _, err = obs.PutString("A", "AAA") expectOk(t, err) - _, err = obs.PutString("C", "CCC") + buf := bytes.NewBufferString("CCC") + objectMetadata := map[string]string{"name": "C", "description": "descC"} + info, err := obs.Put(&nats.ObjectMeta{Name: "C", Metadata: objectMetadata}, buf) expectOk(t, err) + if !reflect.DeepEqual(info.Metadata, objectMetadata) { + t.Fatalf("invalid object metadata: %+v", info.Metadata) + } meta := &nats.ObjectMeta{Name: "A"} meta.Description = "descA" meta.Headers = make(nats.Header) meta.Headers.Set("color", "blue") + objectMetadata["description"] = "updated desc" + objectMetadata["version"] = "0.1" + meta.Metadata = objectMetadata // simple update that does not change the name, just adds data err = obs.UpdateMeta("A", meta) expectOk(t, err) - info, err := obs.GetInfo("A") + info, err = obs.GetInfo("A") expectOk(t, err) - if info.Name != "A" || info.Description != "descA" || info.Headers == nil || info.Headers.Get("color") != "blue" { + if info.Name != "A" || info.Description != "descA" || info.Headers == nil || info.Headers.Get("color") != "blue" || + !reflect.DeepEqual(info.Metadata, objectMetadata) { t.Fatalf("Update failed: %+v", info) } @@ -430,6 +448,7 @@ func TestObjectMetadata(t *testing.T) { meta.Description = "descB" meta.Headers = make(nats.Header) meta.Headers.Set("color", "red") + meta.Metadata = nil err = obs.UpdateMeta("A", meta) expectOk(t, err) @@ -441,7 +460,7 @@ func TestObjectMetadata(t *testing.T) { info, err = obs.GetInfo("B") expectOk(t, err) - if info.Name != "B" || info.Description != "descB" || info.Headers == nil || info.Headers.Get("color") != "red" { + if info.Name != "B" || info.Description != "descB" || info.Headers == nil || info.Headers.Get("color") != "red" || info.Metadata != nil { t.Fatalf("Update failed: %+v", info) }