Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 164 additions & 0 deletions internal/adaptors/dbconfig/dbconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package dbconfig

import (
"fmt"
"strconv"
)

const (
DefaultNamespace = ""
GlobalConfigFile = "/var/run/redis/sonic-db/database_global.json"
ConfigFile = "/var/run/redis/sonic-db/database_config.json"
)

type provider interface {
initialize() error
reset() error
namespaces() ([]string, error)
dbList(namespace string) ([]string, error)
dbID(name, namespace string) (int, error)
dbSeparator(name, namespace string) (string, error)
dbSocket(name, namespace string) (string, error)
dbHostname(name, namespace string) (string, error)
dbPort(name, namespace string) (int, error)
}

var initialized bool

func Init() (err error) {
defer catchException(&err)
initialized = false
return activeProvider.reset()
}

func DbInit() (err error) {
defer catchException(&err)
if initialized {
return nil
}
if err := activeProvider.initialize(); err != nil {
return err
}
initialized = true
return nil
}

func GetDbDefaultNamespace() (string, error) {
return DefaultNamespace, nil
}

func CheckDbMultiNamespace() (multi bool, err error) {
defer catchException(&err)
namespaces, err := GetDbAllNamespaces()
if err != nil {
return false, err
}
return len(namespaces) > 1, nil
}

func GetDbNonDefaultNamespaces() (nonDefault []string, err error) {
defer catchException(&err)
namespaces, err := GetDbAllNamespaces()
if err != nil {
return nil, err
}
nonDefault = make([]string, 0, len(namespaces))
for _, namespace := range namespaces {
if namespace != DefaultNamespace {
nonDefault = append(nonDefault, namespace)
}
}
return nonDefault, nil
}

func GetDbAllNamespaces() (namespaces []string, err error) {
defer catchException(&err)
if err := DbInit(); err != nil {
return nil, err
}
return activeProvider.namespaces()
}

func GetDbNamespaceFromTarget(target string) (namespace string, found bool, err error) {
defer catchException(&err)
if target == DefaultNamespace {
return target, true, nil
}
namespaces, err := GetDbAllNamespaces()
if err != nil {
return "", false, err
}
for _, namespace := range namespaces {
if target == namespace {
return target, true, nil
}
}
return "", false, nil
}

func GetDbList(namespace string) (databases []string, err error) {
defer catchException(&err)
if err := DbInit(); err != nil {
return nil, err
}
return activeProvider.dbList(namespace)
}

func GetDbId(name, namespace string) (id int, err error) {
defer catchException(&err)
if err := DbInit(); err != nil {
return -1, err
}
return activeProvider.dbID(name, namespace)
}

func GetDbSeparator(name, namespace string) (separator string, err error) {
defer catchException(&err)
if err := DbInit(); err != nil {
return "", err
}
return activeProvider.dbSeparator(name, namespace)
}

func GetDbSock(name, namespace string) (socket string, err error) {
defer catchException(&err)
if err := DbInit(); err != nil {
return "", err
}
return activeProvider.dbSocket(name, namespace)
}

func GetDbHostName(name, namespace string) (hostname string, err error) {
defer catchException(&err)
if err := DbInit(); err != nil {
return "", err
}
return activeProvider.dbHostname(name, namespace)
}

func GetDbPort(name, namespace string) (port int, err error) {
defer catchException(&err)
if err := DbInit(); err != nil {
return -1, err
}
return activeProvider.dbPort(name, namespace)
}

func GetDbTcpAddr(name, namespace string) (address string, err error) {
defer catchException(&err)
hostname, err := GetDbHostName(name, namespace)
if err != nil {
return "", err
}
port, err := GetDbPort(name, namespace)
if err != nil {
return "", err
}
return hostname + ":" + strconv.Itoa(port), nil
}

func catchException(err *error) {
if recovered := recover(); recovered != nil {
*err = fmt.Errorf("%v", recovered)
}
}
147 changes: 147 additions & 0 deletions internal/adaptors/dbconfig/provider_pure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
//go:build pure

package dbconfig

import (
"encoding/json"
"errors"
"fmt"
"os"
"sort"
)

const (
defaultDatabaseConfigFile = ConfigFile
defaultGlobalConfigFile = GlobalConfigFile
)

var (
databaseConfigFile = defaultDatabaseConfigFile
globalConfigFile = defaultGlobalConfigFile
activeProvider provider = &fileProvider{}
)

type fileProvider struct {
config databaseConfig
}

type databaseConfig struct {
Instances map[string]instanceConfig `json:"INSTANCES"`
Databases map[string]databaseEntry `json:"DATABASES"`
Includes []json.RawMessage `json:"INCLUDES"`
}

type instanceConfig struct {
Hostname string `json:"hostname"`
Port int `json:"port"`
UnixSocketPath string `json:"unix_socket_path"`
}

type databaseEntry struct {
ID int `json:"id"`
Separator string `json:"separator"`
Instance string `json:"instance"`
}

func (p *fileProvider) initialize() error {
if _, err := os.Stat(globalConfigFile); err == nil {
return fmt.Errorf("global database configuration is not supported by the pure provider")
} else if !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("inspect global database configuration: %w", err)
}

data, err := os.ReadFile(databaseConfigFile)
if err != nil {
return fmt.Errorf("read database configuration: %w", err)
}
if err := json.Unmarshal(data, &p.config); err != nil {
return fmt.Errorf("parse database configuration: %w", err)
}
if len(p.config.Includes) > 0 {
return fmt.Errorf("database configuration INCLUDES are not supported by the pure provider")
}
return nil
}

func (p *fileProvider) reset() error {
p.config = databaseConfig{}
return nil
}

func (p *fileProvider) namespaces() ([]string, error) {
return []string{DefaultNamespace}, nil
}

func (p *fileProvider) dbList(namespace string) ([]string, error) {
if err := validateNamespace(namespace); err != nil {
return nil, err
}
names := make([]string, 0, len(p.config.Databases))
for name := range p.config.Databases {
names = append(names, name)
}
sort.Strings(names)
return names, nil
}

func (p *fileProvider) dbID(name, namespace string) (int, error) {
entry, _, err := p.lookup(name, namespace)
if err != nil {
return -1, err
}
return entry.ID, nil
}

func (p *fileProvider) dbSeparator(name, namespace string) (string, error) {
entry, _, err := p.lookup(name, namespace)
if err != nil {
return "", err
}
return entry.Separator, nil
}

func (p *fileProvider) dbSocket(name, namespace string) (string, error) {
_, instance, err := p.lookup(name, namespace)
if err != nil {
return "", err
}
return instance.UnixSocketPath, nil
}

func (p *fileProvider) dbHostname(name, namespace string) (string, error) {
_, instance, err := p.lookup(name, namespace)
if err != nil {
return "", err
}
return instance.Hostname, nil
}

func (p *fileProvider) dbPort(name, namespace string) (int, error) {
_, instance, err := p.lookup(name, namespace)
if err != nil {
return -1, err
}
return instance.Port, nil
}

func (p *fileProvider) lookup(name, namespace string) (databaseEntry, instanceConfig, error) {
if err := validateNamespace(namespace); err != nil {
return databaseEntry{}, instanceConfig{}, err
}
entry, ok := p.config.Databases[name]
if !ok {
return databaseEntry{}, instanceConfig{}, fmt.Errorf("database %q not present in standalone database configuration", name)
}
instance, ok := p.config.Instances[entry.Instance]
if !ok {
return databaseEntry{}, instanceConfig{}, fmt.Errorf("instance %q for database %q not present in standalone database configuration", entry.Instance, name)
}
return entry, instance, nil
}

func validateNamespace(namespace string) error {
if namespace != DefaultNamespace {
return fmt.Errorf("namespace %q not present in standalone database configuration", namespace)
}
return nil
}
Loading
Loading