diff --git a/core.go b/core.go new file mode 100644 index 000000000..82c37d700 --- /dev/null +++ b/core.go @@ -0,0 +1,163 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cninfra + +import ( + "context" + + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/config" + "go.ligato.io/cn-infra/v2/db/keyval" + "go.ligato.io/cn-infra/v2/health/probe" + "go.ligato.io/cn-infra/v2/health/statuscheck" + "go.ligato.io/cn-infra/v2/logging" + "go.ligato.io/cn-infra/v2/logging/logmanager" + "go.ligato.io/cn-infra/v2/rpc/grpc" + "go.ligato.io/cn-infra/v2/rpc/prometheus" + "go.ligato.io/cn-infra/v2/rpc/rest" + "go.ligato.io/cn-infra/v2/servicelabel" +) + +type Base struct { + ServiceLabel *servicelabel.Plugin // implements: servicelabel.ReaderAPI + StatusCheck *statuscheck.Plugin // implements: statuscheck.PluginStatusWriter, statuscheck.StatusReader + +} + +func (base Base) Start(ctx context.Context) error { + logging.Debugf("Base Start()") + + if err := base.ServiceLabel.InitLabel(); err != nil { + return err + } + if err := base.StatusCheck.StartProbing(); err != nil { + return err + } + + return nil +} + +type Server struct { + HTTP *rest.Plugin // implements: rest.HTTPHandlers + GRPC *grpc.Plugin // implements: grpc.Server +} + +func (server Server) Start(ctx context.Context) error { + logging.Debugf("Server Start()") + + if err := server.HTTP.StartServing(); err != nil { + logging.Fatalf("HTTP serving failed: %v", err) + } + if err := server.GRPC.StartServing(); err != nil { + logging.Fatalf("GRPC serving failed: %v", err) + } + + return nil +} + +type KVStore struct { + keyval.KvProtoPlugin +} + +func ProvideServiceLabelReaderAPI(core Base) servicelabel.ReaderAPI { + if core.ServiceLabel == nil { + return nil + } + return core.ServiceLabel +} + +func ProvideStatusCheckStatusReader(core Base) statuscheck.StatusReader { + if core.StatusCheck == nil { + return nil + } + return core.StatusCheck +} + +func ProvideStatusCheckPluginStatusWriter(core Base) statuscheck.PluginStatusWriter { + if core.StatusCheck == nil { + return nil + } + return core.StatusCheck +} + +var CoreProviders = wire.NewSet( + ProvideServiceLabelReaderAPI, + ProvideStatusCheckStatusReader, + ProvideStatusCheckPluginStatusWriter, +) + +func ProvideRestHTTPHandlers(server Server) rest.HTTPHandlers { + if server.HTTP == nil { + return nil + } + return server.HTTP +} + +func ProvideGrpcServer(server Server) grpc.Server { + if server.GRPC == nil { + return nil + } + return server.GRPC +} + +var ServerProviders = wire.NewSet( + ProvideRestHTTPHandlers, + ProvideGrpcServer, +) + +var WireDefaultCore = wire.NewSet( + servicelabel.WireDefault, + statuscheck.WireDefault, +) + +var WireDefaultServer = wire.NewSet( + rest.WireDefault, + grpc.WireDefault, +) + +var WirePrometheusProbe = wire.NewSet( + probe.WireDefault, + prometheus.WireDefault, +) + +var WireDefaultLogRegistry = wire.NewSet( + wire.InterfaceValue(new(logging.Registry), logging.DefaultRegistry), +) + +var WireDefaultConfig = wire.NewSet( + wire.InterfaceValue(new(config.Config), config.DefaultConfig), +) + +var WireLogManager = wire.NewSet( + WireDefaultLogRegistry, + logmanager.WireDefault, +) + +/*func StatusCheckProvider(deps statuscheck.Deps, conf *statuscheck.Config) (*statuscheck.Plugin, func(), error) { + p := &statuscheck.Plugin{Deps: deps} + p.conf = conf + p.Log = logging.ForPlugin("status-check") + cancel := func() { + if err := p.Close(); err != nil { + p.Log.Error(err) + } + } + return p, cancel, p.Init() +} + +var WireStatusCheck = wire.NewSet( + StatusCheckProvider, +)*/ diff --git a/datasync/resync/plugin_impl_resync.go b/datasync/resync/plugin_impl_resync.go index 4af2b1089..4a6d112b4 100644 --- a/datasync/resync/plugin_impl_resync.go +++ b/datasync/resync/plugin_impl_resync.go @@ -48,6 +48,8 @@ type Deps struct { // Init initializes variables. func (p *Plugin) Init() error { + p.Log.Debug("Init()") + p.registrations = make(map[string]*registration) return nil } diff --git a/datasync/resync/wire.go b/datasync/resync/wire.go new file mode 100644 index 000000000..b25258b61 --- /dev/null +++ b/datasync/resync/wire.go @@ -0,0 +1,37 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package resync + +import ( + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/logging" +) + +var WireDefault = wire.NewSet( + Provider, + wire.Bind(new(Subscriber), new(*Plugin)), +) + +func Provider() (*Plugin, func(), error) { + p := &Plugin{} + p.Log = logging.ForPlugin("resync") + cancel := func() { + if err := p.Close(); err != nil { + p.Log.Error(err) + } + } + return p, cancel, p.Init() +} diff --git a/db/keyval/consul/plugin.go b/db/keyval/consul/plugin.go index 2de3fb3ca..f869e7fca 100644 --- a/db/keyval/consul/plugin.go +++ b/db/keyval/consul/plugin.go @@ -130,14 +130,16 @@ func (p *Plugin) Disabled() bool { func (p *Plugin) getConfig() (*Config, error) { var cfg Config - found, err := p.Cfg.LoadValue(&cfg) - if err != nil { - return nil, err - } - if !found { - p.Log.Info("Consul config not found, skip loading this plugin") - p.disabled = true - return nil, nil + if p.Cfg != nil { + found, err := p.Cfg.LoadValue(&cfg) + if err != nil { + return nil, err + } + if !found { + p.Log.Info("Consul config not found, skip loading this plugin") + p.disabled = true + return nil, nil + } } return &cfg, nil } diff --git a/db/keyval/consul/wire.go b/db/keyval/consul/wire.go new file mode 100644 index 000000000..1a330f8ae --- /dev/null +++ b/db/keyval/consul/wire.go @@ -0,0 +1,46 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package consul + +import ( + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/config" + "go.ligato.io/cn-infra/v2/db/keyval" + "go.ligato.io/cn-infra/v2/logging" +) + +var WireDefault = wire.NewSet( + Provider, + ConfigProvider, + wire.Struct(new(Deps), "StatusCheck", "Resync"), + wire.Bind(new(keyval.KvProtoPlugin), new(*Plugin)), +) + +func ConfigProvider(conf config.Config) *Config { + var cfg Config + if err := conf.UnmarshalKey("consul", &cfg); err != nil { + logging.Errorf("unmarshal key failed: %v", err) + } + return &cfg +} + +func Provider(deps Deps, cfg *Config) (keyval.KvProtoPlugin, func(), error) { + p := &Plugin{} + p.Deps = deps + p.Config = cfg + p.Log = logging.ForPlugin("consul-client") + return p, func() {}, nil +} diff --git a/db/keyval/etcd/config.go b/db/keyval/etcd/config.go index 750f3c29c..f9f2ab524 100644 --- a/db/keyval/etcd/config.go +++ b/db/keyval/etcd/config.go @@ -66,6 +66,8 @@ type ClientConfig struct { } const ( + defaultEndpoint = "127.0.0.1:2379" + // defaultDialTimeout defines the default timeout for connecting to etcd. defaultDialTimeout = 1 * time.Second @@ -76,6 +78,15 @@ const ( defaultSessionTTL = 5 ) +func DefaultConfig() *Config { + return &Config{ + DialTimeout: defaultDialTimeout, + OpTimeout: defaultOpTimeout, + SessionTTL: defaultSessionTTL, + Endpoints: []string{defaultEndpoint}, + } +} + // ConfigToClient transforms yaml configuration modelled by Config // into ClientConfig, which is ready for use with the underlying coreos/etcd // package. @@ -113,7 +124,7 @@ func ConfigToClient(yc *Config) (*ClientConfig, error) { } else if ep := os.Getenv("ETCDV3_ENDPOINTS"); ep != "" { // this provides backwards compatiblity cfg.Endpoints = strings.Split(ep, ",") } else { - cfg.Endpoints = []string{"127.0.0.1:2379"} + cfg.Endpoints = []string{defaultEndpoint} } } diff --git a/db/keyval/etcd/plugin_impl_etcd.go b/db/keyval/etcd/plugin_impl_etcd.go index 1a4f4aa3c..108981327 100644 --- a/db/keyval/etcd/plugin_impl_etcd.go +++ b/db/keyval/etcd/plugin_impl_etcd.go @@ -82,9 +82,11 @@ type Deps struct { // the connection cannot be established. func (p *Plugin) Init() (err error) { // Read ETCD configuration file. Returns error if does not exists. - p.config, err = p.getEtcdConfig() - if err != nil || p.disabled { - return err + if p.config == nil { + p.config, err = p.getEtcdConfig() + if err != nil || p.disabled { + return err + } } // Transforms .yaml config to ETCD client configuration @@ -284,16 +286,18 @@ func (p *Plugin) statusCheckProbe() (statuscheck.PluginState, error) { } func (p *Plugin) getEtcdConfig() (*Config, error) { - var etcdCfg Config - found, err := p.Cfg.LoadValue(&etcdCfg) - if err != nil { - return nil, err - } - if !found { - p.Log.Info("ETCD config not found, skip loading this plugin") - p.disabled = true + var etcdCfg = DefaultConfig() + if p.Cfg != nil { + found, err := p.Cfg.LoadValue(etcdCfg) + if err != nil { + return nil, err + } + if !found { + p.Log.Info("ETCD config not found, skip loading this plugin") + p.disabled = true + } } - return &etcdCfg, nil + return etcdCfg, nil } func (p *Plugin) startPeriodicAutoCompact(period time.Duration) { diff --git a/db/keyval/etcd/wire.go b/db/keyval/etcd/wire.go new file mode 100644 index 000000000..46106ef68 --- /dev/null +++ b/db/keyval/etcd/wire.go @@ -0,0 +1,45 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package etcd + +import ( + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/config" + "go.ligato.io/cn-infra/v2/db/keyval" + "go.ligato.io/cn-infra/v2/logging" +) + +var WireDefault = wire.NewSet( + Provider, + ConfigProvider, + wire.Struct(new(Deps), "StatusCheck", "Resync", "Serializer"), + wire.Bind(new(keyval.KvProtoPlugin), new(*Plugin)), +) + +func ConfigProvider(conf config.Config) *Config { + var cfg = DefaultConfig() + if err := conf.UnmarshalKey("etcd", &cfg); err != nil { + logging.Errorf("unmarshal key failed: %v", err) + } + return cfg +} + +func Provider(deps Deps, cfg *Config) (*Plugin, func(), error) { + p := &Plugin{Deps: deps} + p.config = cfg + p.Log = logging.ForPlugin("etcd-client") + return p, func() {}, nil +} diff --git a/examples/agent/simple/main.go b/examples/agent/simple/main.go new file mode 100644 index 000000000..6adab2d65 --- /dev/null +++ b/examples/agent/simple/main.go @@ -0,0 +1,61 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "go.ligato.io/cn-infra/v2/agent" + "go.ligato.io/cn-infra/v2/db/keyval" + "go.ligato.io/cn-infra/v2/db/keyval/etcd" + "go.ligato.io/cn-infra/v2/infra" + "go.ligato.io/cn-infra/v2/logging" +) + +func main() { + simple := &Simple{ + Broker: &etcd.DefaultPlugin, + } + simple.SetName("simple-agent") + simple.Setup() + + agent.Init( + agent.Name("simple-agent"), + agent.AllPlugins(simple), + ) + + if err := agent.Start(); err != nil { + logging.Fatal(err) + } + if err := agent.Stop(); err != nil { + logging.Fatal(err) + } +} + +type Simple struct { + infra.PluginDeps + Broker keyval.KvProtoPlugin +} + +func (s *Simple) Init() error { + s.Log.Info("running simple") + + root := s.Broker.NewBroker("") + keys, err := root.ListKeys("/") + if err != nil { + return err + } + s.Log.Infof("keys: %+v", keys) + + return nil +} diff --git a/examples/app/basic/main.go b/examples/app/basic/main.go new file mode 100644 index 000000000..f3e455d39 --- /dev/null +++ b/examples/app/basic/main.go @@ -0,0 +1,106 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "go.ligato.io/cn-infra/v2/datasync/kvdbsync" + "go.ligato.io/cn-infra/v2/datasync/resync" + "go.ligato.io/cn-infra/v2/db/keyval" + "go.ligato.io/cn-infra/v2/db/keyval/etcd" + etcdexample "go.ligato.io/cn-infra/v2/examples/model" + "go.ligato.io/cn-infra/v2/health/statuscheck" + "go.ligato.io/cn-infra/v2/infra" + "go.ligato.io/cn-infra/v2/logging" + "go.ligato.io/cn-infra/v2/servicelabel" +) + +func main() { + app := infra.NewApp( + infra.Provide( + provideStatusCheck, + provideResync, + provideEtcd, + provideKVDBSync, + provideServiceLabel, + provideLogger, + ), + infra.Invoke(Example), + ) + app.Run() +} + +func Example(publisher *kvdbsync.Plugin, svclabel servicelabel.ReaderAPI, log logging.PluginLogger) { + log.Print("KeyValPublisher started") + + // Convert data into the proto format. + exampleData := &etcdexample.EtcdExample{ + StringVal: "bla", + Uint32Val: 3, + BoolVal: true, + } + + // PUT: demonstrate how to use the Data Broker Put() API to store + // a simple data structure into ETCD. + label := "/infra/" + svclabel.GetAgentLabel() + "data1" + + log.Infof("Write data to %v", label) + + if err := publisher.Put(label, exampleData); err != nil { + log.Fatal(err) + } +} + +func provideServiceLabel() servicelabel.ReaderAPI { + //p := &servicelabel.Plugin{} + //p.SetName("servicelabel") + //return p + return &servicelabel.DefaultPlugin +} + +func provideLogger() logging.PluginLogger { + return logging.NewParentLogger("infra", logging.DefaultRegistry) +} + +func provideStatusCheck(log logging.PluginLogger) statuscheck.PluginStatusWriter { + p := &statuscheck.Plugin{} + p.SetName("statuscheck") + p.Log = log + return p +} + +func provideResync() resync.Subscriber { + p := &resync.Plugin{} + p.SetName("resync") + p.Log = logging.NewParentLogger("resync2", logging.DefaultRegistry) + return p +} + +func provideEtcd(statuscheck statuscheck.PluginStatusWriter) keyval.KvProtoPlugin { + p := &etcd.Plugin{} + p.SetName("statuscheck") + p.StatusCheck = statuscheck + p.Log = logging.NewParentLogger("statuscheck", logging.DefaultRegistry) + return p +} + +func provideKVDBSync(kvdb keyval.KvProtoPlugin, resyncSub resync.Subscriber) *kvdbsync.Plugin { + p := &kvdbsync.Plugin{} + p.SetName("kvdbsync") + p.KvPlugin = kvdb + p.ResyncOrch = resyncSub + p.ServiceLabel = &servicelabel.DefaultPlugin + p.Log = logging.NewParentLogger("kvdbsync", logging.DefaultRegistry) + return p +} diff --git a/examples/datasync-plugin/etcd.conf b/examples/datasync-plugin/etcd.conf index 42bdd8637..71b3aaab9 100644 --- a/examples/datasync-plugin/etcd.conf +++ b/examples/datasync-plugin/etcd.conf @@ -1,4 +1,5 @@ insecure-transport: true dial-timeout: 1000000000 endpoints: - - "127.0.0.1:2379" +# - "127.0.0.1:2379" + - "172.19.0.3:2379" diff --git a/examples/datasync-plugin/main.go b/examples/datasync-plugin/main.go index de14fc551..55fc95c37 100644 --- a/examples/datasync-plugin/main.go +++ b/examples/datasync-plugin/main.go @@ -13,7 +13,7 @@ import ( "go.ligato.io/cn-infra/v2/datasync/kvdbsync" "go.ligato.io/cn-infra/v2/datasync/resync" "go.ligato.io/cn-infra/v2/db/keyval/etcd" - "go.ligato.io/cn-infra/v2/examples/model" + etcdexample "go.ligato.io/cn-infra/v2/examples/model" "go.ligato.io/cn-infra/v2/infra" "go.ligato.io/cn-infra/v2/servicelabel" ) @@ -42,7 +42,7 @@ func main() { exampleFinished: make(chan struct{}), } p.SetName("datasync-example") - p.SetupLog() + p.Setup() // Start Agent with example plugin including dependencies a := agent.NewAgent( diff --git a/examples/wire/basic/main.go b/examples/wire/basic/main.go new file mode 100644 index 000000000..1cdfdf3e5 --- /dev/null +++ b/examples/wire/basic/main.go @@ -0,0 +1,19 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +func main() { + +} diff --git a/examples/wire/default/main.go b/examples/wire/default/main.go new file mode 100644 index 000000000..1cdfdf3e5 --- /dev/null +++ b/examples/wire/default/main.go @@ -0,0 +1,19 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +func main() { + +} diff --git a/go.mod b/go.mod index 4dafbb99c..5313a79cd 100644 --- a/go.mod +++ b/go.mod @@ -32,6 +32,7 @@ require ( github.com/golang/protobuf v1.3.2 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect github.com/gomodule/redigo v2.0.0+incompatible // indirect + github.com/google/wire v0.4.0 github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/mux v1.6.2 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 @@ -43,8 +44,9 @@ require ( github.com/hashicorp/serf v0.8.1 // indirect github.com/howeyc/crc16 v0.0.0-20171223171357-2b2a61e366a6 github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect + github.com/kr/pretty v0.1.0 github.com/maraino/go-mock v0.0.0-20180321183845-4c74c434cd3a - github.com/mattn/go-isatty v0.0.4 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect github.com/mitchellh/go-homedir v1.0.0 // indirect github.com/mitchellh/go-testing-interface v1.0.0 // indirect github.com/mitchellh/mapstructure v1.1.2 @@ -58,15 +60,18 @@ require ( github.com/sirupsen/logrus v1.4.2 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.6.3 + github.com/stretchr/testify v1.4.0 // indirect github.com/tinylib/msgp v1.0.2 // indirect github.com/unrolled/render v0.0.0-20180914162206-b9786414de4d github.com/willfaught/gockle v0.0.0-20160623235217-4f254e1e0f0a github.com/yuin/gopher-lua v0.0.0-20181031023651-12c4817b42c5 // indirect go.etcd.io/bbolt v1.3.3 // indirect - golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 - golang.org/x/net v0.0.0-20190522155817-f3200d17e092 + go.uber.org/multierr v1.4.0 // indirect + golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 + golang.org/x/net v0.0.0-20190620200207-3b0461eec859 golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d // indirect golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 + golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508 // indirect google.golang.org/genproto v0.0.0-20181101192439-c830210a61df // indirect google.golang.org/grpc v1.21.0 ) diff --git a/go.sum b/go.sum index c6a42ff03..fc734d9a9 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,7 @@ github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 h1:45bxf7AZMw github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis v2.4.5+incompatible h1:Ml+i18wdJPeO/AqNQYpaDyStCAh7TKwLUiaUaQx0yhs= github.com/alicebob/miniredis v2.4.5+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.3.0 h1:B7AQgHi8QSEi4uHu7Sbsga+IJDU+CENgjxoo81vDUqU= @@ -107,6 +108,10 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= +github.com/google/wire v0.4.0 h1:kXcsA/rIGzJImVqPdhfnr6q0xsS9gU0515q1EPpJ9fE= +github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8= @@ -178,8 +183,8 @@ github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzR github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/maraino/go-mock v0.0.0-20180321183845-4c74c434cd3a h1:66Bs2T30mxkg+5ZQEb0z5556Ww4tIBZffUUNnFD5EUQ= github.com/maraino/go-mock v0.0.0-20180321183845-4c74c434cd3a/go.mod h1:KpdDhCgE2rvPhsnLbGZ8Uf1QORj6v92FOgFKnCz5CXM= -github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= @@ -240,6 +245,7 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -269,6 +275,8 @@ github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/tinylib/msgp v1.0.2 h1:DfdQrzQa7Yh2es9SuLkixqxuXS2SxsdYn0KbdrOGWD8= @@ -282,6 +290,7 @@ github.com/willfaught/gockle v0.0.0-20160623235217-4f254e1e0f0a h1:8RS66PasPomNy github.com/willfaught/gockle v0.0.0-20160623235217-4f254e1e0f0a/go.mod h1:NLcF+3nDpXVIZatjn5Z97gKzFFVU7TzgbAcs8G7/Jrs= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yuin/gopher-lua v0.0.0-20181031023651-12c4817b42c5 h1:d9vJ/8gXbVnNk8QFOxFZ7MN7TuHiuvolK1usz5KXVDo= github.com/yuin/gopher-lua v0.0.0-20181031023651-12c4817b42c5/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU= @@ -290,16 +299,27 @@ go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E= +go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -307,14 +327,19 @@ golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -322,8 +347,10 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d h1:62ap6LNOjDU6uGmKXHJbSfciMoV+FeI1sRXx/pLDL44= golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= @@ -334,6 +361,13 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508 h1:0FYNp0PF9kFm/ZUrvcJiQ12IUJJG7iAc6Cu01wbKrbU= +golang.org/x/tools v0.0.0-20191114200427-caa0b0f7d508/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -347,6 +381,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= @@ -359,6 +394,9 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/health/probe/plugin_impl_probe.go b/health/probe/plugin_impl_probe.go index 81f129a66..7cc408eab 100644 --- a/health/probe/plugin_impl_probe.go +++ b/health/probe/plugin_impl_probe.go @@ -66,6 +66,15 @@ func (p *Plugin) Init() error { // AfterInit registers HTTP handlers for liveness and readiness probes. func (p *Plugin) AfterInit() error { + + if err := p.RegisterProbes(); err != nil { + return err + } + + return nil +} + +func (p *Plugin) RegisterProbes() error { if p.StatusCheck == nil { p.Log.Warnf("Unable to register probe handlers, StatusCheck is nil") return nil diff --git a/health/probe/prometheus_probe.go b/health/probe/prometheus_probe.go index e3a14a23e..20f6e56f4 100644 --- a/health/probe/prometheus_probe.go +++ b/health/probe/prometheus_probe.go @@ -88,7 +88,7 @@ func (p *Plugin) registerPrometheusProbe() error { ) allPluginStatusMap := p.StatusCheck.GetAllPluginStatus() for k, v := range allPluginStatusMap { - p.Log.Infof("k=%v, v=%v, state=%v", k, v, v.State) + p.Log.Tracef("k=%v, v=%v, state=%v", k, v, v.State) p.Prometheus.RegisterGaugeFunc(DefaultHealthPath, Namespace, Subsystem, DependencyHealthName, DependencyHealthHelp, @@ -114,11 +114,11 @@ func (p *Plugin) getServiceHealth() float64 { // getDependencyHealth returns plugin health status func (p *Plugin) getDependencyHealth(pluginName string, pluginStatus *status.PluginStatus) func() float64 { - p.Log.Infof("DependencyHealth for plugin %v: %v", pluginName, float64(pluginStatus.State)) + p.Log.Tracef("DependencyHealth for plugin %v: %v", pluginName, float64(pluginStatus.State)) return func() float64 { health := float64(pluginStatus.State) - p.Log.Infof("Dependency Health %v: %v", pluginName, health) + p.Log.Tracef("Dependency Health %v: %v", pluginName, health) return health } } diff --git a/health/probe/wire.go b/health/probe/wire.go new file mode 100644 index 000000000..a64fdcea3 --- /dev/null +++ b/health/probe/wire.go @@ -0,0 +1,32 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package probe + +import ( + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/logging" +) + +var WireDefault = wire.NewSet( + Provider, + wire.Struct(new(Deps), "ServiceLabel", "StatusCheck", "HTTP", "Prometheus"), +) + +func Provider(deps Deps) (*Plugin, error) { + p := &Plugin{Deps: deps} + p.Log = logging.ForPlugin("probe") + return p, p.Init() +} diff --git a/health/statuscheck/model/status/keys_agent_status.go b/health/statuscheck/model/status/keys_agent_status.go index a1eda1ad8..b486cedb9 100644 --- a/health/statuscheck/model/status/keys_agent_status.go +++ b/health/statuscheck/model/status/keys_agent_status.go @@ -14,12 +14,16 @@ package status +import "path" + const ( // StatusPrefix is the relative key prefix for the agent/plugin status. StatusPrefix = "check/status/v1/" // AgentStatusPrefix is the relative key prefix for the agent status, // filtering out statuses of individual plugins. AgentStatusPrefix = StatusPrefix + "agent" + + PluginStatusPrefix = StatusPrefix + "plugin" ) // AgentStatusKey returns the key used in ETCD to store the operational status @@ -31,5 +35,5 @@ func AgentStatusKey() string { // PluginStatusKey returns the key used in ETCD to store the operational status // of the vpp agent plugin. func PluginStatusKey(pluginLabel string) string { - return StatusPrefix + "plugin/" + pluginLabel + return path.Join(PluginStatusPrefix, pluginLabel) } diff --git a/health/statuscheck/plugin_impl_statuscheck.go b/health/statuscheck/plugin_impl_statuscheck.go index a03222777..071721aed 100644 --- a/health/statuscheck/plugin_impl_statuscheck.go +++ b/health/statuscheck/plugin_impl_statuscheck.go @@ -29,16 +29,30 @@ import ( ) var ( - // PeriodicWriteTimeout is frequency of periodic writes of state data into ETCD. - PeriodicWriteTimeout = time.Second * 10 - // PeriodicProbingTimeout is frequency of periodic plugin state probing. - PeriodicProbingTimeout = time.Second * 5 + // DefaultPublishPeriod is frequency of periodic writes of state data into ETCD. + DefaultPublishPeriod = time.Second * 10 + // DefaultProbingPeriod is frequency of periodic plugin state probing. + DefaultProbingPeriod = time.Second * 5 ) +type Config struct { + PublishPeriod time.Duration + ProbingPeriod time.Duration +} + +func DefaultConfig() *Config { + return &Config{ + PublishPeriod: DefaultPublishPeriod, + ProbingPeriod: DefaultProbingPeriod, + } +} + // Plugin struct holds all plugin-related data. type Plugin struct { Deps + conf *Config + access sync.Mutex // lock for the Plugin data agentStat *status.AgentStatus // overall agent status @@ -60,7 +74,13 @@ type Deps struct { // Init prepares the initial status data. func (p *Plugin) Init() error { - // write initial status data into ETCD + p.Log.Debug("Init()") + + if p.conf == nil { + p.conf = DefaultConfig() + } + + // prepare initial status p.agentStat = &status.AgentStatus{ State: status.OperationalState_INIT, BuildVersion: agent.BuildVersion, @@ -69,14 +89,8 @@ func (p *Plugin) Init() error { StartTime: time.Now().Unix(), LastChange: time.Now().Unix(), } - - // initial empty interface status p.interfaceStat = &status.InterfaceStats{} - - // init pluginStat map p.pluginStat = make(map[string]*status.PluginStatus) - - // init map with plugin state probes p.pluginProbe = make(map[string]PluginStateProbe) // prepare context for all go routines @@ -88,65 +102,115 @@ func (p *Plugin) Init() error { // AfterInit starts go routines for periodic probing and periodic updates. // Initial state data are published via the injected transport. func (p *Plugin) AfterInit() error { - p.access.Lock() - defer p.access.Unlock() + if err := p.StartProbing(); err != nil { + return err + } + + return nil +} + +// Close stops go routines for periodic probing and periodic updates. +func (p *Plugin) Close() error { + if p.cancel != nil { + p.cancel() + } + p.wg.Wait() + return nil +} + +func (p *Plugin) StartProbing() error { // do periodic status probing for plugins that have provided the probe function + p.wg.Add(1) go p.periodicProbing(p.ctx) // do periodic updates of the state data in ETCD + p.wg.Add(1) go p.periodicUpdates(p.ctx) - p.publishAgentData() + return p.publishInitial() +} + +func (p *Plugin) publishInitial() error { + p.access.Lock() + defer p.access.Unlock() // transition to OK state if there are no plugins if len(p.pluginStat) == 0 { p.agentStat.State = status.OperationalState_OK p.agentStat.LastChange = time.Now().Unix() - p.publishAgentData() + } + if err := p.publishAgentData(); err != nil { + p.Log.Warnf("publishing agent status failed: %v", err) + return err + } else { + p.Log.Infof("Published agent status") } return nil } -// Close stops go routines for periodic probing and periodic updates. -func (p *Plugin) Close() error { - p.cancel() - p.wg.Wait() +// GetAllPluginStatus returns a map containing pluginname and its status, for all plugins +func (p *Plugin) GetAllPluginStatus() map[string]*status.PluginStatus { + //TODO - used currently, will be removed after incoporating improvements for exposing copy of map + p.access.Lock() + defer p.access.Unlock() - return nil + return p.pluginStat } -// Register a plugin for status change reporting. -func (p *Plugin) Register(pluginName infra.PluginName, probe PluginStateProbe) { +// GetInterfaceStats returns current global operational status of interfaces +func (p *Plugin) GetInterfaceStats() status.InterfaceStats { + p.access.Lock() + defer p.access.Unlock() + + return *p.interfaceStat +} + +// GetAgentStatus return current global operational state of the agent. +func (p *Plugin) GetAgentStatus() status.AgentStatus { p.access.Lock() defer p.access.Unlock() + return *p.agentStat +} + +// Register a plugin for status change reporting. +func (p *Plugin) Register(pluginName infra.PluginName, probe PluginStateProbe) { + if pluginName == "" { + p.Log.Warnf("registering empty plugin name") + return + } stat := &status.PluginStatus{ State: status.OperationalState_INIT, LastChange: time.Now().Unix(), } - p.pluginStat[string(pluginName)] = stat + p.access.Lock() + defer p.access.Unlock() + + p.pluginStat[string(pluginName)] = stat if probe != nil { p.pluginProbe[string(pluginName)] = probe } - // write initial status data into ETCD - p.publishPluginData(pluginName, stat) + p.Log.Tracef("Registered probe: %v", pluginName) - p.Log.Debugf("Plugin %v: status check probe registered", pluginName) + // write initial status data into ETCD + if err := p.publishPluginData(pluginName.String(), stat); err != nil { + p.Log.Warnf("publishing plugin status failed: %v", err) + } } // ReportStateChange can be used to report a change in the status of a previously registered plugin. func (p *Plugin) ReportStateChange(pluginName infra.PluginName, state PluginState, lastError error) { - p.reportStateChange(pluginName, state, lastError) + p.reportStateChange(pluginName.String(), state, lastError) } // ReportStateChangeWithMeta can be used to report a change in the status of a previously registered plugin and report // the specific metadata state func (p *Plugin) ReportStateChangeWithMeta(pluginName infra.PluginName, state PluginState, lastError error, meta proto.Message) { - p.reportStateChange(pluginName, state, lastError) + p.reportStateChange(pluginName.String(), state, lastError) switch data := meta.(type) { case *status.InterfaceStats_Interface: @@ -156,13 +220,13 @@ func (p *Plugin) ReportStateChangeWithMeta(pluginName infra.PluginName, state Pl } } -func (p *Plugin) reportStateChange(pluginName infra.PluginName, state PluginState, lastError error) { +func (p *Plugin) reportStateChange(pluginName string, state PluginState, lastError error) { p.access.Lock() defer p.access.Unlock() - stat, ok := p.pluginStat[string(pluginName)] + stat, ok := p.pluginStat[pluginName] if !ok { - p.Log.Errorf("Unregistered plugin %s is reporting the state, ignoring.", pluginName) + p.Log.Errorf("Unregistered plugin %s is reporting state, ignoring it.", pluginName) return } @@ -180,8 +244,11 @@ func (p *Plugin) reportStateChange(pluginName infra.PluginName, state PluginStat return } - p.Log.WithFields(map[string]interface{}{"plugin": pluginName, "state": state, "lastErr": lastError}). - Info("Agent plugin state update.") + p.Log.WithFields(logging.Fields{ + "plugin": pluginName, + "state": state, + "lastErr": lastError, + }).Info("Agent plugin state update.") // update plugin state stat.State = stateToProto(state) @@ -191,7 +258,9 @@ func (p *Plugin) reportStateChange(pluginName infra.PluginName, state PluginStat } else { stat.Error = "" } - p.publishPluginData(pluginName, stat) + if err := p.publishPluginData(pluginName, stat); err != nil { + p.Log.Warnf("publishing plugin status failed: %v", err) + } // update global state p.agentStat.State = stateToProto(state) @@ -203,7 +272,7 @@ func (p *Plugin) reportStateChange(pluginName infra.PluginName, state PluginStat } var pluginStatusExists bool for _, pluginStatus := range p.agentStat.Plugins { - if pluginStatus.Name == pluginName.String() { + if pluginStatus.Name == pluginName { pluginStatusExists = true pluginStatus.State = stateToProto(state) pluginStatus.Error = lastErr @@ -212,12 +281,14 @@ func (p *Plugin) reportStateChange(pluginName infra.PluginName, state PluginStat // Status for new plugin if !pluginStatusExists { p.agentStat.Plugins = append(p.agentStat.Plugins, &status.PluginStatus{ - Name: pluginName.String(), + Name: pluginName, State: stateToProto(state), Error: lastErr, }) } - p.publishAgentData() + if err := p.publishAgentData(); err != nil { + p.Log.Warnf("publishing agent status failed: %v", err) + } } func (p *Plugin) reportInterfaceStateChange(data *status.InterfaceStats_Interface) { @@ -263,37 +334,41 @@ func (p *Plugin) publishAgentData() error { } // publishPluginData writes the current plugin state into ETCD. -func (p *Plugin) publishPluginData(pluginName infra.PluginName, pluginStat *status.PluginStatus) error { +func (p *Plugin) publishPluginData(pluginName string, pluginStat *status.PluginStatus) error { pluginStat.LastUpdate = time.Now().Unix() if p.Transport != nil { - return p.Transport.Put(status.PluginStatusKey(string(pluginName)), pluginStat) + return p.Transport.Put(status.PluginStatusKey(pluginName), pluginStat) } return nil } -// publishAllData publishes global agent + all plugins state data into ETCD. -func (p *Plugin) publishAllData() { +// publishAll publishes global agent + all plugins state data into ETCD. +func (p *Plugin) publishAll() error { p.access.Lock() defer p.access.Unlock() - p.publishAgentData() + if err := p.publishAgentData(); err != nil { + return err + } for name, s := range p.pluginStat { - p.publishPluginData(infra.PluginName(name), s) + if err := p.publishPluginData(name, s); err != nil { + return err + } } + return nil } // periodicProbing does periodic status probing for all plugins // that have registered probe functions. func (p *Plugin) periodicProbing(ctx context.Context) { - p.wg.Add(1) defer p.wg.Done() for { select { - case <-time.After(PeriodicProbingTimeout): + case <-time.After(p.conf.ProbingPeriod): for pluginName, probe := range p.pluginProbe { - state, lastErr := probe() - p.ReportStateChange(infra.PluginName(pluginName), state, lastErr) + state, err := probe() + p.reportStateChange(pluginName, state, err) // just check in-between probes if the plugin is closing select { case <-ctx.Done(): @@ -311,13 +386,14 @@ func (p *Plugin) periodicProbing(ctx context.Context) { // periodicUpdates does periodic writes of state data into ETCD. func (p *Plugin) periodicUpdates(ctx context.Context) { - p.wg.Add(1) defer p.wg.Done() for { select { - case <-time.After(PeriodicWriteTimeout): - p.publishAllData() + case <-time.After(p.conf.PublishPeriod): + if err := p.publishAll(); err != nil { + p.Log.Warnf("periodic status publishing failed: %v", err) + } case <-ctx.Done(): return @@ -325,37 +401,6 @@ func (p *Plugin) periodicUpdates(ctx context.Context) { } } -// getAgentState return current global operational state of the agent. -func (p *Plugin) getAgentState() status.OperationalState { - p.access.Lock() - defer p.access.Unlock() - return p.agentStat.State -} - -// GetAllPluginStatus returns a map containing pluginname and its status, for all plugins -func (p *Plugin) GetAllPluginStatus() map[string]*status.PluginStatus { - //TODO - used currently, will be removed after incoporating improvements for exposing copy of map - p.access.Lock() - defer p.access.Unlock() - - return p.pluginStat -} - -// GetInterfaceStats returns current global operational status of interfaces -func (p *Plugin) GetInterfaceStats() status.InterfaceStats { - p.access.Lock() - defer p.access.Unlock() - - return *p.interfaceStat -} - -// GetAgentStatus return current global operational state of the agent. -func (p *Plugin) GetAgentStatus() status.AgentStatus { - p.access.Lock() - defer p.access.Unlock() - return *p.agentStat -} - // stateToProto converts agent state type into protobuf agent state type. func stateToProto(state PluginState) status.OperationalState { switch state { diff --git a/health/statuscheck/wire.go b/health/statuscheck/wire.go new file mode 100644 index 000000000..cfa25a4d5 --- /dev/null +++ b/health/statuscheck/wire.go @@ -0,0 +1,54 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package statuscheck + +import ( + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/config" + "go.ligato.io/cn-infra/v2/logging" +) + +var WireDefault = wire.NewSet( + Provider, + ConfigProvider, + NoPublishingDepsProvider, + //wire.Struct(new(Deps), "*"), + wire.Bind(new(PluginStatusWriter), new(*Plugin)), + wire.Bind(new(InterfaceStatusReader), new(*Plugin)), + wire.Bind(new(StatusReader), new(*Plugin)), +) + +func NoPublishingDepsProvider() Deps { + return Deps{ + Transport: nil, + } +} + +func ConfigProvider(conf config.Config) *Config { + var cfg = DefaultConfig() + if err := conf.UnmarshalKey("status-check", &cfg); err != nil { + logging.Errorf("unmarshal key failed: %v", err) + } + return cfg +} + +func Provider(deps Deps, conf *Config) *Plugin { + p := &Plugin{Deps: deps} + p.conf = conf + p.Log = logging.ForPlugin("status-check") + _ = p.Init() // initializes only variables + return p +} diff --git a/logging/logmanager/config.go b/logging/logmanager/config.go index dbde98021..d6dc8c98d 100644 --- a/logging/logmanager/config.go +++ b/logging/logmanager/config.go @@ -1,15 +1,5 @@ package logmanager -// NewConf creates default configuration with InfoLevel & empty loggers. -// Suitable also for usage in flavor to programmatically specify default behavior. -func NewConf() *Config { - return &Config{ - DefaultLevel: "", - Loggers: []LoggerConfig{}, - Hooks: make(map[string]HookConfig), - } -} - // Config is a binding that supports to define default log levels for multiple loggers type Config struct { DefaultLevel string `json:"default-level"` @@ -21,7 +11,7 @@ type Config struct { // Currently we support only logger level. type LoggerConfig struct { Name string - Level string //debug, info, warn, error, fatal, panic + Level string // levels: debug, info, warn, error, fatal, panic } // HookConfig contains configuration of hook services @@ -31,3 +21,12 @@ type HookConfig struct { Port int Levels []string } + +// DefaultConfig creates default configuration +func DefaultConfig() *Config { + return &Config{ + DefaultLevel: "info", + Loggers: []LoggerConfig{}, + Hooks: make(map[string]HookConfig), + } +} diff --git a/logging/logmanager/options.go b/logging/logmanager/options.go index b9297521b..03fb8f0d9 100644 --- a/logging/logmanager/options.go +++ b/logging/logmanager/options.go @@ -40,6 +40,6 @@ func UseDeps(cb func(*Deps)) Option { // UseConf returns Option which injects a particular configuration. func UseConf(conf Config) Option { return func(p *Plugin) { - p.Config = &conf + p.config = &conf } } diff --git a/logging/logmanager/plugin_impl_log_manager.go b/logging/logmanager/plugin_impl_log_manager.go index 72cbd5fc7..f478ee3dc 100644 --- a/logging/logmanager/plugin_impl_log_manager.go +++ b/logging/logmanager/plugin_impl_log_manager.go @@ -44,7 +44,7 @@ const ( type Plugin struct { Deps - *Config + config *Config } // Deps groups dependencies injected into the plugin so that they are @@ -58,59 +58,66 @@ type Deps struct { // Init does nothing func (p *Plugin) Init() error { - if p.Cfg != nil { - if p.Config == nil { - p.Config = NewConf() - } + p.Log.Debug("Init()") - _, err := p.Cfg.LoadValue(p.Config) + if p.config == nil { + p.config = DefaultConfig() + } + if p.Cfg != nil { + _, err := p.Cfg.LoadValue(p.config) if err != nil { return err } - p.Log.Debugf("logs config: %+v", p.Config) + } + p.Log.Debugf("logs config: %+v", p.config) - // Handle default log level. Prefer value from environmental variable - defaultLogLvl := os.Getenv("INITIAL_LOGLVL") - if defaultLogLvl == "" { - defaultLogLvl = p.Config.DefaultLevel - } - if defaultLogLvl != "" { - if err := p.LogRegistry.SetLevel("default", defaultLogLvl); err != nil { - p.Log.Warnf("setting default log level failed: %v", err) - } else { - // All loggers created up to this point were created with initial log level set (defined - // via INITIAL_LOGLVL env. variable with value 'info' by default), so at first, let's set default - // log level for all of them. - for loggerName := range p.LogRegistry.ListLoggers() { - logger, exists := p.LogRegistry.Lookup(loggerName) - if !exists { - continue - } - lvl, _ := logging.ParseLogLevel(defaultLogLvl) - logger.SetLevel(lvl) + // Handle default log level. Prefer value from environmental variable + defaultLogLvl := os.Getenv("INITIAL_LOGLVL") + if defaultLogLvl == "" { + defaultLogLvl = p.config.DefaultLevel + } + if defaultLogLvl != "" { + if err := p.LogRegistry.SetLevel("default", defaultLogLvl); err != nil { + p.Log.Fatalf("setting default log level failed: %v", err) + } else { + // All loggers created up to this point were created with initial log level set (defined + // via INITIAL_LOGLVL env. variable with value 'info' by default), so at first, let's set default + // log level for all of them. + for loggerName := range p.LogRegistry.ListLoggers() { + logger, exists := p.LogRegistry.Lookup(loggerName) + if !exists { + continue } + lvl, _ := logging.ParseLogLevel(defaultLogLvl) + logger.SetLevel(lvl) } } + } - // Handle config file log levels - for _, logCfgEntry := range p.Config.Loggers { - // Put log/level entries from configuration file to the registry. - if err := p.LogRegistry.SetLevel(logCfgEntry.Name, logCfgEntry.Level); err != nil { - // Intentionally just log warn & not propagate the error (it is minor thing to interrupt startup) - p.Log.Warnf("setting log level %s for logger %s failed: %v", - logCfgEntry.Level, logCfgEntry.Name, err) - } + // Handle config file log levels + for _, logCfgEntry := range p.config.Loggers { + // Put log/level entries from configuration file to the registry. + if err := p.LogRegistry.SetLevel(logCfgEntry.Name, logCfgEntry.Level); err != nil { + // Intentionally just log warn & not propagate the error (it is minor thing to interrupt startup) + p.Log.Warnf("setting log level %s for logger %s failed: %v", + logCfgEntry.Level, logCfgEntry.Name, err) } - if len(p.Config.Hooks) > 0 { - p.Log.Info("configuring log hooks") - for hookName, hookConfig := range p.Config.Hooks { - if err := p.addHook(hookName, hookConfig); err != nil { - p.Log.Warnf("configuring log hook %s failed: %v", hookName, err) - } + } + if len(p.config.Hooks) > 0 { + p.Log.Info("configuring log hooks") + for hookName, hookConfig := range p.config.Hooks { + if err := p.addHook(hookName, hookConfig); err != nil { + p.Log.Warnf("configuring log hook %s failed: %v", hookName, err) } } } + if p.HTTP != nil { + p.HTTP.RegisterHTTPHandler(fmt.Sprintf("/log/{%s}/{%s}", + loggerVarName, levelVarName), p.logLevelHandler, "PUT") + p.HTTP.RegisterHTTPHandler("/log/list", p.listLoggersHandler, "GET") + } + return nil } @@ -120,11 +127,6 @@ func (p *Plugin) Init() error { // - Set log level for a registered logger: // > curl -X PUT http://localhost:/log// func (p *Plugin) AfterInit() error { - if p.HTTP != nil { - p.HTTP.RegisterHTTPHandler(fmt.Sprintf("/log/{%s}/{%s}", - loggerVarName, levelVarName), p.logLevelHandler, "PUT") - p.HTTP.RegisterHTTPHandler("/log/list", p.listLoggersHandler, "GET") - } return nil } diff --git a/logging/logmanager/wire.go b/logging/logmanager/wire.go new file mode 100644 index 000000000..7f8c374db --- /dev/null +++ b/logging/logmanager/wire.go @@ -0,0 +1,44 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logmanager + +import ( + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/config" + "go.ligato.io/cn-infra/v2/logging" +) + +var WireDefault = wire.NewSet( + ConfigProvider, + Provider, + wire.Struct(new(Deps), "ServiceLabel", "LogRegistry", "HTTP"), +) + +func ConfigProvider(conf config.Config) *Config { + var cfg = DefaultConfig() + if err := conf.UnmarshalKey("logs", &cfg); err != nil { + logging.Errorf("unmarshal key failed: %v", err) + } + return cfg +} + +func Provider(deps Deps, conf *Config) (*Plugin, error) { + p := new(Plugin) + p.Deps = deps + p.config = conf + p.Log = logging.ForPlugin("logmanager") + return p, p.Init() +} diff --git a/logging/logrus/caller.go b/logging/logrus/caller.go index a5e6b7b26..245ccc71d 100644 --- a/logging/logrus/caller.go +++ b/logging/logrus/caller.go @@ -21,6 +21,7 @@ import ( ) const ( + cninfraModulePath = "go.ligato.io/cn-infra/v2/" sirupsenLogrusPkgPath = "sirupsen/logrus." maximumCallerDepth = 15 diff --git a/logging/logrus/formatter.go b/logging/logrus/formatter.go index 83451ac1f..e125e5f0d 100644 --- a/logging/logrus/formatter.go +++ b/logging/logrus/formatter.go @@ -63,18 +63,53 @@ func NewFormatter() *Formatter { return &Formatter{ Formatter: &logrus.TextFormatter{ EnvironmentOverrideColors: true, - TimestampFormat: "2006-01-02 15:04:05.00000", - SortingFunc: sortKeys, + //TimestampFormat: "2006-01-02 15:04:05.00000", + //TimestampFormat: "2006-01-02 15:04:05.00000", + //FullTimestamp: true, + SortingFunc: sortKeys, }, } } +const ( + red = 31 + yellow = 33 + blue = 36 + gray = 37 + black = 90 +) + func (f *Formatter) Format(entry *logrus.Entry) ([]byte, error) { + var levelColor int + switch entry.Level { + case logrus.TraceLevel: + levelColor = black + case logrus.DebugLevel: + levelColor = gray + case logrus.WarnLevel: + levelColor = yellow + case logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel: + levelColor = red + default: + levelColor = blue + } + if levelColor == int(logrus.TraceLevel) { + entry.Message = fmt.Sprintf("\x1b[%dm%s\x1b[0m", levelColor, entry.Message) + } + + // Convert value of logger field into message prefix + if prefix, ok := entry.Data[LoggerKey]; ok { + entry.Message = fmt.Sprintf("\x1b[%dm%s\x1b[0m ‣ %s", levelColor, prefix, entry.Message) + delete(entry.Data, LoggerKey) + } + + // Resolve caller function location if f.Function || f.Location { if caller := getCaller(); caller != nil { data := logrus.Fields{} if f.Function { - data[FunctionKey] = caller.Function + function := strings.TrimPrefix(caller.Function, cninfraModulePath) + data[FunctionKey] = function } if f.Location { file := caller.File @@ -90,5 +125,6 @@ func (f *Formatter) Format(entry *logrus.Entry) ([]byte, error) { entry.Data = data } } + return f.Formatter.Format(entry) } diff --git a/logging/logrus/logger.go b/logging/logrus/logger.go index f6334435f..5e9c58915 100644 --- a/logging/logrus/logger.go +++ b/logging/logrus/logger.go @@ -33,10 +33,24 @@ var initialLogLvl = logging.InfoLevel func init() { if lvl, err := logging.ParseLogLevel(os.Getenv("INITIAL_LOGLVL")); err == nil { initialLogLvl = lvl - defaultFormatter.Location = initialLogLvl >= logging.DebugLevel - defaultFormatter.Function = initialLogLvl >= logging.TraceLevel + //defaultFormatter.Location = initialLogLvl >= logging.DebugLevel + //defaultFormatter.Function = initialLogLvl >= logging.TraceLevel defaultLogger.SetLevel(lvl) defaultLogger.Tracef("initial log level: %v", lvl.String()) + if err := defaultRegistry.SetLevel("default", initialLogLvl.String()); err != nil { + defaultLogger.Fatalf("setting default log level failed: %v", err) + } else { + // All loggers created up to this point were created with initial log level set (defined + // via INITIAL_LOGLVL env. variable with value 'info' by default), so at first, let's set default + // log level for all of them. + for loggerName := range defaultRegistry.ListLoggers() { + logger, exists := defaultRegistry.Lookup(loggerName) + if !exists { + continue + } + logger.SetLevel(lvl) + } + } } logging.DefaultLogger = DefaultLogger() } @@ -206,7 +220,9 @@ func (logger *Logger) entryWithFields(fields logging.Fields) *logrus.Entry { for k, v := range redactData(fields) { data[k] = v } - data[LoggerKey] = logger.name + if _, ok := data[LoggerKey]; !ok { + data[LoggerKey] = logger.name + } return logger.Logger.WithFields(data) } diff --git a/logging/logrus/registry.go b/logging/logrus/registry.go index b1ada0801..f23232e59 100644 --- a/logging/logrus/registry.go +++ b/logging/logrus/registry.go @@ -67,7 +67,9 @@ func checkLoggerName(name string) error { // refer the logger in registry. func (lr *LogRegistry) NewLogger(name string) logging.Logger { if existingLogger := lr.getLoggerFromMapping(name); existingLogger != nil { - panic(fmt.Errorf("logger with name '%s' already exists", name)) + //panic(fmt.Errorf("logger with name '%s' already exists", name)) + fmt.Printf("logger with name '%s' already exists, returning previous logger\n", name) + return existingLogger } if err := checkLoggerName(name); err != nil { panic(err) diff --git a/logging/parent.go b/logging/parent.go index 96101495d..6ec952fb2 100644 --- a/logging/parent.go +++ b/logging/parent.go @@ -54,7 +54,7 @@ type PluginLogger interface { // and optionally created children (their name prefixed by plugin logger name) func ForPlugin(name string) PluginLogger { if logger, found := DefaultRegistry.Lookup(name); found { - DefaultLogger.Tracef("using plugin logger for %q that was already initialized", name) + //DefaultLogger.Tracef("using plugin logger for %q that was already initialized", name) return &ParentLogger{ Logger: logger, Prefix: name, diff --git a/rpc/grpc/config.go b/rpc/grpc/config.go index 9fa62d8d1..f01466e84 100644 --- a/rpc/grpc/config.go +++ b/rpc/grpc/config.go @@ -29,9 +29,24 @@ import ( "go.ligato.io/cn-infra/v2/infra" ) +const ( + DefaultHost = "0.0.0.0" + DefaultHTTPPort = "9111" + DefaultEndpoint = DefaultHost + ":" + DefaultHTTPPort +) + +func DefaultConfig() *Config { + return &Config{ + Endpoint: DefaultEndpoint, + } +} + // Config is a configuration for GRPC netListener // It is meant to be extended with security (TLS...) type Config struct { + // Disabled disables plugin + Disabled bool `json:"disabled"` + // Endpoint is an address of GRPC netListener Endpoint string `json:"endpoint"` diff --git a/rpc/grpc/options.go b/rpc/grpc/options.go index 768353473..087a53107 100644 --- a/rpc/grpc/options.go +++ b/rpc/grpc/options.go @@ -16,7 +16,6 @@ package grpc import ( "crypto/tls" - "fmt" grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" "golang.org/x/time/rate" @@ -45,11 +44,10 @@ func NewPlugin(opts ...Option) *Plugin { p.Deps.Log = logging.ForPlugin(p.String()) } if p.Deps.Cfg == nil { - p.Deps.Cfg = config.ForPlugin(p.String(), - config.WithExtraFlags(func(flags *config.FlagSet) { - flags.String(grpcPortFlag(p.PluginName), "", fmt.Sprintf( - "Configure %q server port", p.String())) - })) + p.Deps.Cfg = config.ForPlugin(p.String()) /*config.WithExtraFlags(func(flags *config.FlagSet) { + flags.String(grpcPortFlag(p.PluginName), "", fmt.Sprintf( + "Configure %q server port", p.String())) + })*/ } return p diff --git a/rpc/grpc/plugin_api_grpc.go b/rpc/grpc/plugin_api_grpc.go index 5654b55e6..997d7e729 100644 --- a/rpc/grpc/plugin_api_grpc.go +++ b/rpc/grpc/plugin_api_grpc.go @@ -21,7 +21,7 @@ import ( // Server defines the API for getting grpc.Server instance that // is useful for registering new GRPC services type Server interface { - // Server is a getter for accessing grpc.Server (of a GRPC plugin) + // GetServer is a getter for accessing grpc.Server (of a GRPC plugin) // // Example usage: // diff --git a/rpc/grpc/plugin_impl_grpc.go b/rpc/grpc/plugin_impl_grpc.go index 957dff632..49b65d4e1 100644 --- a/rpc/grpc/plugin_impl_grpc.go +++ b/rpc/grpc/plugin_impl_grpc.go @@ -43,9 +43,6 @@ type Plugin struct { *Config - // Plugin availability flag - disabled bool - // GRPC server instance grpcServer *grpc.Server // GRPC network listener @@ -66,13 +63,19 @@ type Deps struct { // Init prepares GRPC netListener for registration of individual service func (p *Plugin) Init() (err error) { + p.Log.Debug("Init()") + // Get GRPC configuration file if p.Config == nil { p.Config, err = p.getGrpcConfig() - if err != nil || p.disabled { + if err != nil { return err } } + if p.Config.Disabled { + p.Log.Infof("grpc server disabled via config") + return nil + } // Prepare GRPC server if p.grpcServer == nil { @@ -141,15 +144,6 @@ func (p *Plugin) Init() (err error) { } grpclog.SetLoggerV2(grpcLogger) - return nil -} - -// AfterInit starts the HTTP netListener. -func (p *Plugin) AfterInit() (err error) { - if p.disabled { - return nil - } - if p.Deps.HTTP != nil { p.Log.Infof("exposing GRPC services via HTTP (port %v) on: /service", p.Deps.HTTP.GetPort()) p.Deps.HTTP.RegisterHTTPHandler("/service", func(formatter *render.Render) http.HandlerFunc { @@ -159,17 +153,19 @@ func (p *Plugin) AfterInit() (err error) { p.Log.Debugf("HTTP not set, skip exposing GRPC services") } - // initialize prometheus metrics for grpc server - if p.metrics != nil { - p.metrics.InitializeMetrics(p.grpcServer) + return nil +} + +// AfterInit starts the HTTP netListener. +func (p *Plugin) AfterInit() (err error) { + if p.Config.Disabled { + return nil } - // Start GRPC listener - p.netListener, err = ListenAndServe(p.Config, p.grpcServer) + err = p.StartServing() if err != nil { return err } - p.Log.Infof("Listening GRPC on: %v", p.Config.Endpoint) return nil } @@ -190,18 +186,33 @@ func (p *Plugin) GetServer() *grpc.Server { // IsDisabled returns *true* if the plugin is not in use due to missing // grpc configuration. func (p *Plugin) IsDisabled() bool { - return p.disabled + return p.Config.Disabled } func (p *Plugin) getGrpcConfig() (*Config, error) { - var grpcCfg Config - found, err := p.Cfg.LoadValue(&grpcCfg) + grpcCfg := DefaultConfig() + found, err := p.Cfg.LoadValue(grpcCfg) if err != nil { - return &grpcCfg, err + return grpcCfg, err } if !found { - p.Log.Info("GRPC config not found, skip loading this plugin") - p.disabled = true + p.Log.Infof("GRPC config not found, using default config: %+v", grpcCfg) + } + return grpcCfg, nil +} + +func (p *Plugin) StartServing() (err error) { + // initialize prometheus metrics for grpc server + if p.metrics != nil { + p.metrics.InitializeMetrics(p.grpcServer) } - return &grpcCfg, nil + + // Start GRPC listener + p.netListener, err = ListenAndServe(p.Config, p.grpcServer) + if err != nil { + return err + } + p.Log.Infof("Listening GRPC on: %v", p.Config.Endpoint) + + return nil } diff --git a/rpc/grpc/wire.go b/rpc/grpc/wire.go new file mode 100644 index 000000000..98748c8c5 --- /dev/null +++ b/rpc/grpc/wire.go @@ -0,0 +1,50 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grpc + +import ( + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/config" + "go.ligato.io/cn-infra/v2/logging" +) + +var WireDefault = wire.NewSet( + Provider, + ConfigProvider, + wire.Struct(new(Deps), "HTTP"), + wire.Bind(new(Server), new(*Plugin)), +) + +func ConfigProvider(conf config.Config) *Config { + var cfg = DefaultConfig() + if err := conf.UnmarshalKey("grpc", &cfg); err != nil { + logging.Errorf("unmarshal key failed: %v", err) + } + return cfg +} + +func Provider(deps Deps, conf *Config) (*Plugin, func(), error) { + p := &Plugin{} + p.Deps = deps + p.Config = conf + p.Log = logging.ForPlugin("grpc-server") + cancel := func() { + if err := p.Close(); err != nil { + p.Log.Error(err) + } + } + return p, cancel, p.Init() +} diff --git a/rpc/prometheus/plugin_impl_prometheus.go b/rpc/prometheus/plugin_impl_prometheus.go index d65b9c5ed..f2841a928 100644 --- a/rpc/prometheus/plugin_impl_prometheus.go +++ b/rpc/prometheus/plugin_impl_prometheus.go @@ -80,6 +80,13 @@ func (p *Plugin) Init() error { // AfterInit registers HTTP handlers. func (p *Plugin) AfterInit() error { + + p.RegisterHandlers() + + return nil +} + +func (p *Plugin) RegisterHandlers() { if p.HTTP != nil { p.Lock() defer p.Unlock() @@ -91,8 +98,6 @@ func (p *Plugin) AfterInit() error { } else { p.Log.Info("Unable to register Prometheus metrics handlers, HTTP is nil") } - - return nil } // Close cleans up the allocated resources. @@ -190,7 +195,7 @@ func (p *Plugin) RegisterGaugeFunc(registryPath string, namespace string, subsys p.Log.Errorf("GaugeFunc('%s') registration failed: %s", gaugeName, err) return err } - p.Log.Infof("GaugeFunc('%s') registered.", gaugeName) + p.Log.Tracef("GaugeFunc('%s') registered.", gaugeName) return nil } diff --git a/rpc/prometheus/wire.go b/rpc/prometheus/wire.go new file mode 100644 index 000000000..4046c90ac --- /dev/null +++ b/rpc/prometheus/wire.go @@ -0,0 +1,33 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package prometheus + +import ( + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/logging" +) + +var WireDefault = wire.NewSet( + Provider, + wire.Struct(new(Deps), "HTTP"), + wire.Bind(new(API), new(*Plugin)), +) + +func Provider(deps Deps) (*Plugin, error) { + p := &Plugin{Deps: deps} + p.Log = logging.ForPlugin("prometheus") + return p, p.Init() +} diff --git a/rpc/rest/options.go b/rpc/rest/options.go index c58889bf7..1cd005755 100644 --- a/rpc/rest/options.go +++ b/rpc/rest/options.go @@ -17,11 +17,11 @@ package rest import ( "fmt" + "golang.org/x/time/rate" + "go.ligato.io/cn-infra/v2/config" "go.ligato.io/cn-infra/v2/logging" "go.ligato.io/cn-infra/v2/utils/ratelimit" - - "golang.org/x/time/rate" ) // DefaultPlugin is a default instance of Plugin. @@ -43,8 +43,9 @@ func NewPlugin(opts ...Option) *Plugin { if p.Deps.Cfg == nil { p.Deps.Cfg = config.ForPlugin(p.String(), config.WithExtraFlags(func(flags *config.FlagSet) { - flags.String(httpPortFlag(p.PluginName), DefaultHTTPPort, fmt.Sprintf( - "Configure %q server port", p.String())) + flags.String("http-port", DefaultHTTPPort, fmt.Sprintf("Configure %q server port", p.String())) + f := flags.Lookup("http-port") + config.DefaultConfig.BindFlag("http.port", f) })) } diff --git a/rpc/rest/plugin_impl_rest.go b/rpc/rest/plugin_impl_rest.go index 0d8505ab1..278693f82 100644 --- a/rpc/rest/plugin_impl_rest.go +++ b/rpc/rest/plugin_impl_rest.go @@ -55,14 +55,18 @@ type Deps struct { // Init is the plugin entry point called by Agent Core // - It prepares Gorilla MUX HTTP Router func (p *Plugin) Init() (err error) { + p.Log.Debug("Init()") + if p.Config == nil { p.Config = DefaultConfig() } - if err := PluginConfig(p.Cfg, p.Config, p.PluginName); err != nil { - return err + if p.Cfg != nil { + if err := PluginConfig(p.Cfg, p.Config, p.PluginName); err != nil { + return err + } } if p.Config.Disabled { - p.Log.Debugf("Init skipped (plugin disabled)") + p.Log.Debugf("Disabling HTTP server") return nil } @@ -108,19 +112,11 @@ func (p *Plugin) AfterInit() (err error) { return nil } - h := p.makeHandler() - - p.server, err = ListenAndServe(*p.Config, h) + err = p.StartServing() if err != nil { return err } - if p.Config.UseHTTPS() { - p.Log.Info("Serving on https://", p.Config.Endpoint) - } else { - p.Log.Info("Serving on http://", p.Config.Endpoint) - } - return nil } @@ -129,7 +125,7 @@ func (p *Plugin) RegisterHTTPHandler(path string, provider HandlerProvider, meth if p.Config.Disabled { return nil } - p.Log.Debugf("Registering handler: %s", path) + p.Log.Tracef("Registering handler: %s", path) return p.mx.Handle(path, provider(p.formatter)).Methods(methods...) } @@ -137,7 +133,7 @@ func (p *Plugin) RegisterHTTPHandler(path string, provider HandlerProvider, meth // RegisterPermissionGroup adds new permission group if token authentication is enabled func (p *Plugin) RegisterPermissionGroup(group ...*access.PermissionGroup) { if p.Config.EnableTokenAuth { - p.Log.Debugf("Registering permission group(s): %s", group) + p.Log.Tracef("Registering permission group(s): %s", group) p.auth.AddPermissionGroup(group...) } } @@ -155,14 +151,20 @@ func (p *Plugin) Close() error { if p.Config.Disabled { return nil } - return p.server.Close() + if p.server != nil { + if err := p.server.Close(); err != nil { + return err + } + } + return nil } -func (p *Plugin) makeHandler() http.Handler { +func (p *Plugin) Router() *mux.Router { var ( authFunc func(r *http.Request) (string, error) permFunc func(user string, r *http.Request) error ) + if p.Config.EnableTokenAuth { authFunc = p.auth.AuthorizeRequest permFunc = p.auth.IsPermitted @@ -189,3 +191,22 @@ func (p *Plugin) makeHandler() http.Handler { return p.mx } + +func (p *Plugin) StartServing() error { + var err error + + h := p.Router() + + p.server, err = ListenAndServe(*p.Config, h) + if err != nil { + return err + } + + if p.Config.UseHTTPS() { + p.Log.Info("Serving on https://", p.Config.Endpoint) + } else { + p.Log.Info("Serving on http://", p.Config.Endpoint) + } + + return nil +} diff --git a/rpc/rest/wire.go b/rpc/rest/wire.go new file mode 100644 index 000000000..e5e72140e --- /dev/null +++ b/rpc/rest/wire.go @@ -0,0 +1,51 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package rest + +import ( + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/config" + "go.ligato.io/cn-infra/v2/logging" +) + +var WireDefault = wire.NewSet( + Provider, + ConfigProvider, + wire.Bind(new(HTTPHandlers), new(*Plugin)), + wire.Struct(new(Deps), "Authenticator"), + wire.InterfaceValue(new(BasicHTTPAuthenticator), (BasicHTTPAuthenticator)(nil)), +) + +func ConfigProvider(conf config.Config) *Config { + var cfg = DefaultConfig() + if err := conf.UnmarshalKey("http", &cfg); err != nil { + logging.Errorf("unmarshal key failed: %v", err) + } + return cfg +} + +func Provider(deps Deps, conf *Config) (*Plugin, func(), error) { + p := &Plugin{} + p.Deps = deps + p.Config = conf + p.Log = logging.ForPlugin("http-server") + cancel := func() { + if err := p.Close(); err != nil { + p.Log.Error(err) + } + } + return p, cancel, p.Init() +} diff --git a/servicelabel/plugin_impl_servicelabel.go b/servicelabel/plugin_impl_servicelabel.go index a2efc7759..ec42ea96a 100644 --- a/servicelabel/plugin_impl_servicelabel.go +++ b/servicelabel/plugin_impl_servicelabel.go @@ -15,12 +15,14 @@ package servicelabel import ( + "fmt" "path" flag "github.com/spf13/pflag" "go.ligato.io/cn-infra/v2/config" "go.ligato.io/cn-infra/v2/infra" + "go.ligato.io/cn-infra/v2/logging" "go.ligato.io/cn-infra/v2/logging/logrus" ) @@ -44,12 +46,28 @@ type Plugin struct { MicroserviceLabel string } -// Init is called at plugin initialization. -func (p *Plugin) Init() error { +func (p *Plugin) InitLabel() error { if p.MicroserviceLabel == "" { p.MicroserviceLabel = config.GetString("microservice-label") } + + if p.MicroserviceLabel == "" { + return fmt.Errorf("microservice-label is empty") + } + logrus.DefaultLogger().Debugf("Microservice label is set to %v", p.MicroserviceLabel) + + return nil +} + +// Init is called at plugin initialization. +func (p *Plugin) Init() error { + logging.DefaultLogger.WithField("logger", "servicelabel").Debug("Init()") + + if err := p.InitLabel(); err != nil { + return err + } + return nil } diff --git a/servicelabel/wire.go b/servicelabel/wire.go new file mode 100644 index 000000000..7f03f240a --- /dev/null +++ b/servicelabel/wire.go @@ -0,0 +1,27 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package servicelabel + +import "github.com/google/wire" + +var WireDefault = wire.NewSet( + Provider, + wire.Bind(new(ReaderAPI), new(*Plugin)), +) + +func Provider() *Plugin { + p := &Plugin{} + return p +} diff --git a/wire.go b/wire.go new file mode 100644 index 000000000..495895086 --- /dev/null +++ b/wire.go @@ -0,0 +1,59 @@ +// Copyright (c) 2020 Cisco and/or its affiliates. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//+build wireinject + +package cninfra + +import ( + "context" + + "github.com/google/wire" + + "go.ligato.io/cn-infra/v2/config" + "go.ligato.io/cn-infra/v2/health/statuscheck" + "go.ligato.io/cn-infra/v2/rpc/grpc" + "go.ligato.io/cn-infra/v2/rpc/rest" + "go.ligato.io/cn-infra/v2/servicelabel" +) + +//go:generate wire + +func InjectDefaultBase(ctx context.Context, conf config.Config) (Base, func(), error) { + wire.Build( + //WireDefaultLogRegistry, + //logmanager.WireDefault, + + servicelabel.WireDefault, + statuscheck.WireDefault, + + wire.Struct(new(Base), "*"), + ) + return Base{}, nil, nil +} + +func InjectDefaultServer(ctx context.Context, conf config.Config) (Server, func(), error) { + wire.Build( + rest.WireDefault, + grpc.WireDefault, + + wire.Struct(new(Server), "*"), + ) + return Server{}, nil, nil +} + +var WireDefaultAll = wire.NewSet( + InjectDefaultBase, + InjectDefaultServer, +) diff --git a/wire_gen.go b/wire_gen.go new file mode 100644 index 000000000..9907e64de --- /dev/null +++ b/wire_gen.go @@ -0,0 +1,71 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate wire +//+build !wireinject + +package cninfra + +import ( + "context" + "github.com/google/wire" + "go.ligato.io/cn-infra/v2/config" + "go.ligato.io/cn-infra/v2/health/statuscheck" + "go.ligato.io/cn-infra/v2/rpc/grpc" + "go.ligato.io/cn-infra/v2/rpc/rest" + "go.ligato.io/cn-infra/v2/servicelabel" +) + +// Injectors from wire.go: + +func InjectDefaultBase(ctx context.Context, conf config.Config) (Base, func(), error) { + plugin := servicelabel.Provider() + deps := statuscheck.NoPublishingDepsProvider() + statuscheckConfig := statuscheck.ConfigProvider(conf) + statuscheckPlugin := statuscheck.Provider(deps, statuscheckConfig) + base := Base{ + ServiceLabel: plugin, + StatusCheck: statuscheckPlugin, + } + return base, func() { + }, nil +} + +func InjectDefaultServer(ctx context.Context, conf config.Config) (Server, func(), error) { + basicHTTPAuthenticator := _wireBasicHTTPAuthenticatorValue + deps := rest.Deps{ + Authenticator: basicHTTPAuthenticator, + } + restConfig := rest.ConfigProvider(conf) + plugin, cleanup, err := rest.Provider(deps, restConfig) + if err != nil { + return Server{}, nil, err + } + grpcDeps := grpc.Deps{ + HTTP: plugin, + } + grpcConfig := grpc.ConfigProvider(conf) + grpcPlugin, cleanup2, err := grpc.Provider(grpcDeps, grpcConfig) + if err != nil { + cleanup() + return Server{}, nil, err + } + server := Server{ + HTTP: plugin, + GRPC: grpcPlugin, + } + return server, func() { + cleanup2() + cleanup() + }, nil +} + +var ( + _wireBasicHTTPAuthenticatorValue = (rest.BasicHTTPAuthenticator)(nil) +) + +// wire.go: + +var WireDefaultAll = wire.NewSet( + InjectDefaultBase, + InjectDefaultServer, +)