feat(bsr): populate container meta from meta files

This commit is contained in:
irenarindos authored and Timothy Messier committed 2023-05-31 12:18:20 +00:00
1 parent 4e5401da7d
commit d06c9b2933
6 files changed
+324 -13

No files matched your search

+254 -11
View File
@@ -4,10 +4,13 @@
package bsr
import (
"bufio"
"context"
"errors"
"fmt"
"io"
"strconv"
"strings"
"github.com/hashicorp/boundary/internal/bsr/internal/checksum"
"github.com/hashicorp/boundary/internal/bsr/internal/is"
@@ -30,6 +33,159 @@ const (
pubKeySelfSignatureFile = "pubKeySelfSignature.sign"
)
// decodeSessionMeta will populate a SessionMeta for an opened BSR Session
// TODO Unmarshal without brute force
func decodeSessionMeta(ctx context.Context, r io.Reader) (*SessionMeta, error) {
const op = "bsr.decodeSessionMeta"
switch {
case r == nil:
return nil, fmt.Errorf("%s: missing session meta file: %w", op, ErrInvalidParameter)
}
s := &SessionMeta{}
user := &User{Scope: Scope{}}
target := &Target{Scope: Scope{}}
sHost := &StaticHost{Catalog: StaticHostCatalog{}}
dHost := &DynamicHost{Catalog: DynamicHostCatalog{}}
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
if len(l) == 0 {
continue
}
k, v, ok := strings.Cut(l, ":")
if !ok {
return nil, fmt.Errorf("%s: session meta file contains invalid entry; expecting k: v pair:%s", op, l)
}
v = strings.TrimSpace(v)
switch {
case k == "id":
s.Id = v
case k == "protocol":
s.Protocol = Protocol(v)
// User
case k == "user_publicId":
user.PublicId = v
case k == "user_name":
user.Name = v
case k == "user_description":
user.Description = v
case k == "user_scope_publicId":
user.Scope.PublicId = v
case k == "user_scope_name":
user.Scope.Name = v
case k == "user_scope_description":
user.Scope.Description = v
case k == "user_scope_type":
user.Scope.Type = v
case k == "user_scope_parentId":
user.Scope.ParentId = v
case k == "user_scope_primaryAuthMethod":
user.Scope.PrimaryAuthMethodId = v
// Target
case k == "target_publicId":
target.PublicId = v
case k == "target_projectId":
target.ProjectId = v
case k == "target_name":
target.Name = v
case k == "target_description":
target.Description = v
case k == "target_defaultPort":
dp, err := strconv.Atoi(v)
if err != nil {
return nil, err
}
target.DefaultPort = uint32(dp)
case k == "target_sessionMaxSeconds":
sms, err := strconv.Atoi(v)
if err != nil {
return nil, err
}
target.SessionMaxSeconds = uint32(sms)
case k == "target_sessionConnectionLimit":
scl, err := strconv.Atoi(v)
if err != nil {
return nil, err
}
target.SessionConnectionLimit = int32(scl)
case k == "target_workerFilter":
target.WorkerFilter = v
case k == "target_egressWorkerFilter":
target.EgressWorkerFilter = v
case k == "target_ingressWorkerFilter":
target.IngressWorkerFilter = v
case k == "target_scope_publicId":
target.Scope.PublicId = v
case k == "target_scope_name":
target.Scope.Name = v
case k == "target_scope_description":
target.Scope.Description = v
case k == "target_scope_type":
target.Scope.Type = v
case k == "target_scope_parentId":
target.Scope.ParentId = v
case k == "target_scope_primaryAuthMethod":
target.Scope.PrimaryAuthMethodId = v
// Static Host
case k == "staticHost_publicId":
sHost.PublicId = v
case k == "staticHost_name":
sHost.Name = v
case k == "staticHost_description":
sHost.Description = v
case k == "staticHost_address":
sHost.Address = v
case k == "staticHostCatalog_publicId":
sHost.Catalog.PublicId = v
case k == "staticHostCatalog_projectId":
sHost.Catalog.ProjectId = v
case k == "staticHostCatalog_name":
sHost.Catalog.Name = v
case k == "staticHostCatalog_description":
sHost.Catalog.Description = v
// Dynamic Host
case k == "dynamicHost_publicId":
dHost.PublicId = v
case k == "dynamicHost_name":
dHost.Name = v
case k == "dynamicHost_description":
dHost.Description = v
case k == "dynamicHost_externalId":
dHost.ExternalId = v
case k == "dynamicHostCatalog_publicId":
dHost.Catalog.PublicId = v
case k == "dynamicHostCatalog_projectId":
dHost.Catalog.ProjectId = v
case k == "dynamicHostCatalog_name":
dHost.Catalog.Name = v
case k == "dynamicHostCatalog_description":
dHost.Catalog.Description = v
case k == "dynamicHostCatalog_pluginId":
dHost.Catalog.PluginId = v
case k == "dynamicHostCatalog_attributes":
dHost.Catalog.Attributes = v
}
}
s.Target = target
s.User = user
if sHost.PublicId != "" {
s.StaticHost = sHost
}
if dHost.PublicId != "" {
s.DynamicHost = dHost
}
return s, nil
}
// Session is the top level container in a bsr that contains the files for
// a recorded session.
type Session struct {
@@ -150,6 +306,51 @@ func OpenSession(ctx context.Context, sessionRecordingId string, f storage.FS, k
panic("not implemented")
}
// ConnectionMeta contains metadata about a connection in a BSR.
type ConnectionMeta struct {
Id string
}
func (c ConnectionMeta) isValid() bool {
switch {
case c.Id == "":
return false
default:
return true
}
}
// decodeConnectionMeta will populate the ConnectionMeta for a BSR Connection
// TODO Unmarshal without brute force
func decodeConnectionMeta(ctx context.Context, r io.Reader) (*ConnectionMeta, error) {
const op = "bsr.decodeConnectionMeta"
switch {
case r == nil:
return nil, fmt.Errorf("%s: missing connection meta file: %w", op, ErrInvalidParameter)
}
c := &ConnectionMeta{}
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
if len(l) == 0 {
continue
}
k, v, ok := strings.Cut(l, ":")
if !ok {
return nil, fmt.Errorf("%s: connection meta file contains invalid entry; expecting k: v pair:%s", op, l)
}
v = strings.TrimSpace(v)
switch {
case k == "id":
c.Id = v
}
}
return c, nil
}
// NewConnection creates a Connection container for a given connection id.
func (s *Session) NewConnection(ctx context.Context, meta *ConnectionMeta) (*Connection, error) {
const op = "bsr.(Session).NewConnection"
@@ -189,11 +390,6 @@ func (s *Session) Close(ctx context.Context) error {
return s.container.close(ctx)
}
// ConnectionMeta contains metadata about a connection in a BSR.
type ConnectionMeta struct {
Id string
}
// Connection is a container in a bsr for a specific connection in a session
// container. It contains the files for the recorded connection.
type Connection struct {
@@ -203,6 +399,56 @@ type Connection struct {
Meta *ConnectionMeta
}
// ChannelMeta contains metadata about a channel in a BSR.
type ChannelMeta struct {
Id string
Type string
}
func (c ChannelMeta) isValid() bool {
switch {
case c.Id == "":
return false
case c.Type == "":
return false
default:
return true
}
}
// decodeChannelMeta will populate the ChannelMeta for a BSR Channel
// TODO Unmarshal without brute force
func decodeChannelMeta(ctx context.Context, r io.Reader) (*ChannelMeta, error) {
const op = "bsr.decodeChannelMeta"
switch {
case r == nil:
return nil, fmt.Errorf("%s: missing channel meta file: %w", op, ErrInvalidParameter)
}
c := &ChannelMeta{}
scanner := bufio.NewScanner(r)
for scanner.Scan() {
l := scanner.Text()
if len(l) == 0 {
continue
}
k, v, ok := strings.Cut(l, ":")
if !ok {
return nil, fmt.Errorf("%s: channel meta file contains invalid entry; expecting k: v pair:%s", op, l)
}
v = strings.TrimSpace(v)
switch {
case k == "id":
c.Id = v
case k == "channelType":
c.Type = v
}
}
return c, nil
}
// NewChannel creates a Channel container for a given channel id.
func (c *Connection) NewChannel(ctx context.Context, meta *ChannelMeta) (*Channel, error) {
const op = "bsr.(Connection).NewChannel"
@@ -233,6 +479,9 @@ func (c *Connection) NewChannel(ctx context.Context, meta *ChannelMeta) (*Channe
if _, err := nc.WriteMeta(ctx, "id", meta.Id); err != nil {
return nil, err
}
if _, err := nc.WriteMeta(ctx, "channelType", meta.Type); err != nil {
return nil, err
}
return &Channel{
container: nc,
Meta: meta,
@@ -288,12 +537,6 @@ func (c *Connection) Close(ctx context.Context) error {
return c.container.close(ctx)
}
// ChannelMeta contains metadata about a channel in a BSR.
type ChannelMeta struct {
Id string
Type string
}
// Channel is a container in a bsr for a specific channel in a session
// container. It contains the files for the recorded channel.
type Channel struct {
+1 -1
View File
@@ -282,7 +282,7 @@ func TestBsr(t *testing.T) {
createdChannels := make([]*channel, 0, len(conn.channels))
for _, chann := range conn.channels {
ch, err := c.NewChannel(ctx, &bsr.ChannelMeta{Id: chann.id})
ch, err := c.NewChannel(ctx, &bsr.ChannelMeta{Id: chann.id, Type: "chan"})
require.NoError(t, err)
require.NotNil(t, ch)
+66
View File
@@ -0,0 +1,66 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package bsr
import (
"context"
"testing"
"github.com/hashicorp/boundary/internal/bsr/internal/fstest"
"github.com/hashicorp/boundary/internal/bsr/kms"
"github.com/stretchr/testify/require"
)
func TestPopulateMeta(t *testing.T) {
ctx := context.Background()
keys, err := kms.CreateKeys(ctx, kms.TestWrapper(t), "session")
require.NoError(t, err)
sessionId := "session"
sessionProtocol := "SSH"
// Populate session meta
sessionMeta := TestSessionMeta(sessionId, Protocol((sessionProtocol)))
s, err := NewSession(ctx, sessionMeta, &fstest.MemFS{}, keys, WithSupportsMultiplex(true))
require.NoError(t, err)
require.NotNil(t, s)
// Reset meta and populate it from the meta file
s.Meta = &SessionMeta{}
sm, err := decodeSessionMeta(ctx, s.container.meta)
require.NoError(t, err)
s.Meta = sm
require.Equal(t, s.Meta.Id, sessionId)
require.Equal(t, s.Meta.Protocol.ToText(), sessionProtocol)
require.Equal(t, s.Meta.Target, sessionMeta.Target)
require.Equal(t, s.Meta.User, sessionMeta.User)
require.Equal(t, s.Meta.StaticHost, sessionMeta.StaticHost)
// Populate connection meta
connectionId := "connection"
c, err := s.NewConnection(ctx, &ConnectionMeta{Id: connectionId})
require.NoError(t, err)
require.NotNil(t, c)
c.Meta = &ConnectionMeta{}
cm, err := decodeConnectionMeta(ctx, c.container.meta)
require.NoError(t, err)
c.Meta = cm
require.Equal(t, c.Meta.Id, connectionId)
// Populate channel meta
channelId := "channel"
channelType := "mythical"
ch, err := c.NewChannel(ctx, &ChannelMeta{Id: channelId, Type: channelType})
require.NoError(t, err)
require.NotNil(t, ch)
ch.Meta = &ChannelMeta{}
chM, err := decodeChannelMeta(ctx, ch.container.meta)
require.NoError(t, err)
ch.Meta = chM
require.Equal(t, ch.Meta.Id, channelId)
require.Equal(t, ch.Meta.Type, channelType)
}
@@ -2,5 +2,5 @@ e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-inbou
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-inbound.data
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 messages-outbound.data
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 requests-outbound.data
e30a207b53f444c7bd2d1e8cc102abf910dfafd70aaef7f24db00298832b74d3 channel.meta
27a58452605f6e30ca048cc540e9d963c7270212fcb2c7b73fc69e314ffd1902 channel.meta
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 channel.summary
@@ -1,4 +1,5 @@
id: chan_1
channelType: chan
messages: inbound
requests: inbound
messages: outbound
@@ -1 +1,2 @@
id: chan_1
channelType: chan