ipfs-cluster/consensus/crdt/config.go
2019-08-27 19:18:50 +02:00

194 lines
5.0 KiB
Go

package crdt
import (
"encoding/json"
"errors"
"fmt"
"time"
"github.com/ipfs/ipfs-cluster/api"
"github.com/ipfs/ipfs-cluster/config"
peer "github.com/libp2p/go-libp2p-core/peer"
"github.com/kelseyhightower/envconfig"
)
var configKey = "crdt"
var envConfigKey = "cluster_crdt"
// Default configuration values
var (
DefaultClusterName = "ipfs-cluster"
DefaultPeersetMetric = "ping"
DefaultDatastoreNamespace = "/c" // from "/crdt"
DefaultRebroadcastInterval = time.Minute
DefaultTrustedPeers = []peer.ID{}
DefaultTrustAll = true
)
// Config is the configuration object for Consensus.
type Config struct {
config.Saver
hostShutdown bool
// The topic we wish to subscribe to
ClusterName string
// TrustAll specifies whether we should trust all peers regardless of
// the TrustedPeers contents.
TrustAll bool
// Any update received from a peer outside this set is ignored and not
// forwarded. Trusted peers can also access additional RPC endpoints
// for this peer that are forbidden for other peers.
TrustedPeers []peer.ID
// The interval before re-announcing the current state
// to the network when no activity is observed.
RebroadcastInterval time.Duration
// The name of the metric we use to obtain the peerset (every peer
// with valid metric of this type is part of it).
PeersetMetric string
// All keys written to the datastore will be namespaced with this prefix
DatastoreNamespace string
// Tracing enables propagation of contexts across binary boundaries.
Tracing bool
}
type jsonConfig struct {
ClusterName string `json:"cluster_name"`
TrustedPeers []string `json:"trusted_peers"`
RebroadcastInterval string `json:"rebroadcast_interval,omitempty"`
PeersetMetric string `json:"peerset_metric,omitempty"`
DatastoreNamespace string `json:"datastore_namespace,omitempty"`
}
// ConfigKey returns the section name for this type of configuration.
func (cfg *Config) ConfigKey() string {
return configKey
}
// Validate returns an error if the configuration has invalid values.
func (cfg *Config) Validate() error {
if cfg.ClusterName == "" {
return errors.New("crdt.cluster_name cannot be empty")
}
if cfg.PeersetMetric == "" {
return errors.New("crdt.peerset_metric needs a name")
}
if cfg.RebroadcastInterval <= 0 {
return errors.New("crdt.rebroadcast_interval is invalid")
}
return nil
}
// LoadJSON takes a raw JSON slice and sets all the configuration fields.
func (cfg *Config) LoadJSON(raw []byte) error {
jcfg := &jsonConfig{}
err := json.Unmarshal(raw, jcfg)
if err != nil {
return fmt.Errorf("error unmarshaling %s config", configKey)
}
cfg.Default()
return cfg.applyJSONConfig(jcfg)
}
func (cfg *Config) applyJSONConfig(jcfg *jsonConfig) error {
config.SetIfNotDefault(jcfg.ClusterName, &cfg.ClusterName)
// Whenever we parse JSON, TrustAll is false unless an '*' peer exists
cfg.TrustAll = false
for _, p := range jcfg.TrustedPeers {
if p == "*" {
cfg.TrustAll = true
cfg.TrustedPeers = []peer.ID{}
break
}
pid, err := peer.IDB58Decode(p)
if err != nil {
return fmt.Errorf("error parsing trusted peers: %s", err)
}
cfg.TrustedPeers = append(cfg.TrustedPeers, pid)
}
config.SetIfNotDefault(jcfg.PeersetMetric, &cfg.PeersetMetric)
config.SetIfNotDefault(jcfg.DatastoreNamespace, &cfg.DatastoreNamespace)
config.ParseDurations(
"crdt",
&config.DurationOpt{Duration: jcfg.RebroadcastInterval, Dst: &cfg.RebroadcastInterval, Name: "rebroadcast_interval"},
)
return cfg.Validate()
}
// ToJSON returns the JSON representation of this configuration.
func (cfg *Config) ToJSON() ([]byte, error) {
jcfg := cfg.toJSONConfig()
return config.DefaultJSONMarshal(jcfg)
}
func (cfg *Config) toJSONConfig() *jsonConfig {
jcfg := &jsonConfig{
ClusterName: cfg.ClusterName,
PeersetMetric: "",
RebroadcastInterval: "",
}
if cfg.TrustAll {
jcfg.TrustedPeers = []string{"*"}
} else {
jcfg.TrustedPeers = api.PeersToStrings(cfg.TrustedPeers)
}
if cfg.PeersetMetric != DefaultPeersetMetric {
jcfg.PeersetMetric = cfg.PeersetMetric
// otherwise leave empty/hidden
}
if cfg.DatastoreNamespace != DefaultDatastoreNamespace {
jcfg.DatastoreNamespace = cfg.DatastoreNamespace
// otherwise leave empty/hidden
}
if cfg.RebroadcastInterval != DefaultRebroadcastInterval {
jcfg.RebroadcastInterval = cfg.RebroadcastInterval.String()
}
return jcfg
}
// Default sets the configuration fields to their default values.
func (cfg *Config) Default() error {
cfg.ClusterName = DefaultClusterName
cfg.RebroadcastInterval = DefaultRebroadcastInterval
cfg.PeersetMetric = DefaultPeersetMetric
cfg.DatastoreNamespace = DefaultDatastoreNamespace
cfg.TrustedPeers = DefaultTrustedPeers
cfg.TrustAll = DefaultTrustAll
return nil
}
// ApplyEnvVars fills in any Config fields found
// as environment variables.
func (cfg *Config) ApplyEnvVars() error {
jcfg := cfg.toJSONConfig()
err := envconfig.Process(envConfigKey, jcfg)
if err != nil {
return err
}
return cfg.applyJSONConfig(jcfg)
}