Skip to content

Commit

Permalink
Merge pull request #833 from kaleido-io/ns-section
Browse files Browse the repository at this point in the history
Namespace config validation
  • Loading branch information
shorsher authored May 26, 2022
2 parents 1bb1675 + b7b389e commit ac42fb9
Show file tree
Hide file tree
Showing 11 changed files with 743 additions and 229 deletions.
3 changes: 3 additions & 0 deletions docs/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,10 @@ nav_order: 3
|Key|Description|Type|Default Value|
|---|-----------|----|-------------|
|description|A description for the namespace|`string`|`<nil>`
|mode|The namespace mode. Valid values: gateway, multiparty|`string`|`<nil>`
|name|The name of the namespace (must be unique)|`string`|`<nil>`
|plugins|The list of plugins for this namespace|`string`|`<nil>`
|remoteName|The namespace name to be sent in plugin calls, if it differs from namespace name|`string`|`<nil>`

## node

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/golang-migrate/migrate/v4 v4.15.1
github.com/gorilla/mux v1.8.0
github.com/gorilla/websocket v1.5.0
github.com/hyperledger/firefly-common v0.1.5
github.com/hyperledger/firefly-common v0.1.6
github.com/jarcoal/httpmock v1.1.0
github.com/karlseguin/ccache v2.0.3+incompatible
github.com/lib/pq v1.10.4
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,8 @@ github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hyperledger/firefly-common v0.1.5 h1:66RXEAc/dsSEYPRye3G48Lk9sN+AmYGPf1FkrkbQGWs=
github.com/hyperledger/firefly-common v0.1.5/go.mod h1:qGy7i8eWlE8Ed7jFn2Hpn8bYaflL204j4NJB1mAfTms=
github.com/hyperledger/firefly-common v0.1.6 h1:I6t7N5D3YlaPSGknYF2xLurfEO+UQsHV4VFYeR/3UI4=
github.com/hyperledger/firefly-common v0.1.6/go.mod h1:qGy7i8eWlE8Ed7jFn2Hpn8bYaflL204j4NJB1mAfTms=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
Expand Down
10 changes: 8 additions & 2 deletions internal/coreconfig/coreconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ const (
PluginConfigName = "name"
// PluginConfigType is the type of the plugin to be loaded
PluginConfigType = "type"
// NamespaceName is a short name for a pre-defined namespace
// NamespaceMode is the configured mode of a namespace
NamespaceMode = "mode"
// NamespaceRemoteName is the namespace name to be sent in plugin calls
NamespaceRemoteName = "remoteName"
// NamespacePlugins is the list of namespace plugins
NamespacePlugins = "plugins"
// NamespaceName is the short name for a pre-defined namespace
NamespaceName = "name"
// NamespaceName is a long description for a pre-defined namespace
// NamespaceName is the long description for a pre-defined namespace
NamespaceDescription = "description"
)

Expand Down
3 changes: 3 additions & 0 deletions internal/coremsgs/en_config_descriptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ var (
ConfigNamespacesDefault = ffc("config.namespaces.default", "The default namespace - must be in the predefined list", i18n.StringType)
ConfigNamespacesPredefined = ffc("config.namespaces.predefined", "A list of namespaces to ensure exists, without requiring a broadcast from the network", "List "+i18n.StringType)
ConfigNamespacesPredefinedName = ffc("config.namespaces.predefined[].name", "The name of the namespace (must be unique)", i18n.StringType)
ConfigNamespacesPredefinedPlugins = ffc("config.namespaces.predefined[].plugins", "The list of plugins for this namespace", i18n.StringType)
ConfigNamespacesPredefinedMode = ffc("config.namespaces.predefined[].mode", "The namespace mode. Valid values: gateway, multiparty", i18n.StringType)
ConfigNamespacesPredefinedRemoteName = ffc("config.namespaces.predefined[].remoteName", "The namespace name to be sent in plugin calls, if it differs from namespace name", i18n.StringType)
ConfigNamespacesPredefinedDescription = ffc("config.namespaces.predefined[].description", "A description for the namespace", i18n.StringType)

ConfigNodeDescription = ffc("config.node.description", "The description of this FireFly node", i18n.StringType)
Expand Down
422 changes: 215 additions & 207 deletions internal/coremsgs/en_error_messages.go

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions internal/namespace/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ var (
func InitConfig(withDefaults bool) {
namespacePredefined.AddKnownKey(coreconfig.NamespaceName)
namespacePredefined.AddKnownKey(coreconfig.NamespaceDescription)
namespacePredefined.AddKnownKey(coreconfig.NamespaceRemoteName)
namespacePredefined.AddKnownKey(coreconfig.NamespacePlugins)
namespacePredefined.AddKnownKey(coreconfig.NamespaceMode, "multiparty")
if withDefaults {
namespaceConfig.AddKnownKey(NamespacePredefined+".0."+coreconfig.NamespaceName, "default")
namespaceConfig.AddKnownKey(NamespacePredefined+".0."+coreconfig.NamespaceDescription, "Default predefined namespace")
Expand Down
161 changes: 155 additions & 6 deletions internal/namespace/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,12 @@ import (
"github.com/hyperledger/firefly-common/pkg/log"
"github.com/hyperledger/firefly/internal/coreconfig"
"github.com/hyperledger/firefly/internal/coremsgs"
"github.com/hyperledger/firefly/pkg/blockchain"
"github.com/hyperledger/firefly/pkg/core"
"github.com/hyperledger/firefly/pkg/database"
"github.com/hyperledger/firefly/pkg/dataexchange"
"github.com/hyperledger/firefly/pkg/sharedstorage"
"github.com/hyperledger/firefly/pkg/tokens"
)

type Manager interface {
Expand All @@ -36,14 +40,24 @@ type Manager interface {
}

type namespaceManager struct {
ctx context.Context
nsConfig map[string]config.Section
ctx context.Context
nsConfig map[string]config.Section
bcPlugins map[string]blockchain.Plugin
dbPlugins map[string]database.Plugin
dxPlugins map[string]dataexchange.Plugin
ssPlugins map[string]sharedstorage.Plugin
tokensPlugins map[string]tokens.Plugin
}

func NewNamespaceManager(ctx context.Context) Manager {
func NewNamespaceManager(ctx context.Context, bc map[string]blockchain.Plugin, db map[string]database.Plugin, dx map[string]dataexchange.Plugin, ss map[string]sharedstorage.Plugin, tokens map[string]tokens.Plugin) Manager {
nm := &namespaceManager{
ctx: ctx,
nsConfig: buildNamespaceMap(ctx),
ctx: ctx,
nsConfig: buildNamespaceMap(ctx),
bcPlugins: bc,
dbPlugins: db,
dxPlugins: dx,
ssPlugins: ss,
tokensPlugins: tokens,
}
return nm
}
Expand Down Expand Up @@ -80,7 +94,7 @@ func (nm *namespaceManager) getPredefinedNamespaces(ctx context.Context) ([]*cor
i := 0
foundDefault := false
for name, nsObject := range nm.nsConfig {
if err := core.ValidateFFNameField(ctx, name, fmt.Sprintf("namespaces.predefined[%d].name", i)); err != nil {
if err := nm.validateNamespaceConfig(ctx, name, i, nsObject); err != nil {
return nil, err
}
i++
Expand Down Expand Up @@ -124,3 +138,138 @@ func (nm *namespaceManager) initNamespaces(ctx context.Context, di database.Plug
}
return nil
}

func (nm *namespaceManager) validateNamespaceConfig(ctx context.Context, name string, index int, conf config.Section) error {
if err := core.ValidateFFNameField(ctx, name, fmt.Sprintf("namespaces.predefined[%d].name", index)); err != nil {
return err
}

if name == core.SystemNamespace || conf.GetString(coreconfig.NamespaceRemoteName) == core.SystemNamespace {
return i18n.NewError(ctx, coremsgs.MsgFFSystemReservedName, core.SystemNamespace)
}

mode := conf.GetString(coreconfig.NamespaceMode)
plugins := conf.GetStringSlice(coreconfig.NamespacePlugins)

// If no plugins are found when querying the config, assume older config file
if len(plugins) == 0 {
for plugin := range nm.bcPlugins {
plugins = append(plugins, plugin)
}

for plugin := range nm.dxPlugins {
plugins = append(plugins, plugin)
}

for plugin := range nm.ssPlugins {
plugins = append(plugins, plugin)
}

for plugin := range nm.dbPlugins {
plugins = append(plugins, plugin)
}
}

switch mode {
// Multiparty is the default mode when none is provided
case "multiparty":
if err := nm.validateMultiPartyConfig(ctx, name, plugins); err != nil {
return err
}
case "gateway":
if err := nm.validateGatewayConfig(ctx, name, plugins); err != nil {
return err
}
default:
return i18n.NewError(ctx, coremsgs.MsgInvalidNamespaceMode, name)
}
return nil
}

func (nm *namespaceManager) validateMultiPartyConfig(ctx context.Context, name string, plugins []string) error {
var dbPlugin bool
var ssPlugin bool
var dxPlugin bool
var bcPlugin bool

for _, pluginName := range plugins {
if _, ok := nm.bcPlugins[pluginName]; ok {
if bcPlugin {
return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain")
}
bcPlugin = true
continue
}
if _, ok := nm.dxPlugins[pluginName]; ok {
if dxPlugin {
return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "dataexchange")
}
dxPlugin = true
continue
}
if _, ok := nm.ssPlugins[pluginName]; ok {
if ssPlugin {
return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "sharedstorage")
}
ssPlugin = true
continue
}
if _, ok := nm.dbPlugins[pluginName]; ok {
if dbPlugin {
return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database")
}
dbPlugin = true
continue
}
if _, ok := nm.tokensPlugins[pluginName]; ok {
continue
}

return i18n.NewError(ctx, coremsgs.MsgNamespaceUnknownPlugin, name, pluginName)
}

if !dbPlugin || !ssPlugin || !dxPlugin || !bcPlugin {
return i18n.NewError(ctx, coremsgs.MsgNamespaceMultipartyConfiguration, name)
}

return nil
}

func (nm *namespaceManager) validateGatewayConfig(ctx context.Context, name string, plugins []string) error {
var dbPlugin bool
var bcPlugin bool

for _, pluginName := range plugins {
if _, ok := nm.bcPlugins[pluginName]; ok {
if bcPlugin {
return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "blockchain")
}
bcPlugin = true
continue
}
if _, ok := nm.dxPlugins[pluginName]; ok {
return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayInvalidPlugins, name)
}
if _, ok := nm.ssPlugins[pluginName]; ok {
return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayInvalidPlugins, name)
}
if _, ok := nm.dbPlugins[pluginName]; ok {
if dbPlugin {
return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayMultiplePluginType, name, "database")
}
dbPlugin = true
continue
}
if _, ok := nm.tokensPlugins[pluginName]; ok {
continue
}

return i18n.NewError(ctx, coremsgs.MsgNamespaceUnknownPlugin, name, pluginName)
}

if !dbPlugin {
return i18n.NewError(ctx, coremsgs.MsgNamespaceGatewayNoDB, name)
}

return nil
}
Loading

0 comments on commit ac42fb9

Please sign in to comment.