Skip to content

Commit

Permalink
Introduce Named Services (#1509)
Browse files Browse the repository at this point in the history
  • Loading branch information
refs authored Apr 21, 2021
1 parent 9f6ab8e commit 8171b41
Show file tree
Hide file tree
Showing 18 changed files with 634 additions and 3 deletions.
5 changes: 5 additions & 0 deletions changelog/unreleased/named-services.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Enhancement: Named Service Registration

move away from hardcoding service IP addresses and rely upon name resolution instead. It delegates the address lookup to a static in-memory service registry, which can be re-implemented in multiple forms.

https://github.com/cs3org/reva/pull/1509
13 changes: 11 additions & 2 deletions cmd/revad/runtime/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package runtime

import (
"github.com/cs3org/reva/pkg/registry"
"github.com/rs/zerolog"
)

Expand All @@ -27,10 +28,11 @@ type Option func(o *Options)

// Options defines the available options for this package.
type Options struct {
Logger *zerolog.Logger
Logger *zerolog.Logger
Registry registry.Registry
}

// newOptions intializes the available default options.
// newOptions initializes the available default options.
func newOptions(opts ...Option) Options {
opt := Options{}

Expand All @@ -47,3 +49,10 @@ func WithLogger(logger *zerolog.Logger) Option {
o.Logger = logger
}
}

// WithRegistry provides a function to set the registry.
func WithRegistry(r registry.Registry) Option {
return func(o *Options) {
o.Registry = r
}
}
20 changes: 20 additions & 0 deletions cmd/revad/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ import (
"strconv"
"strings"

"github.com/cs3org/reva/pkg/registry/memory"

"github.com/cs3org/reva/pkg/utils"

"contrib.go.opencensus.io/exporter/jaeger"
"github.com/cs3org/reva/cmd/revad/internal/grace"
"github.com/cs3org/reva/pkg/logger"
Expand Down Expand Up @@ -56,6 +60,21 @@ func RunWithOptions(mainConf map[string]interface{}, pidFile string, opts ...Opt
parseSharedConfOrDie(mainConf["shared"])
coreConf := parseCoreConfOrDie(mainConf["core"])

// TODO: one can pass the options from the config file to registry.New() and initialize a registry based upon config files.
if options.Registry != nil {
utils.GlobalRegistry = options.Registry
} else if _, ok := mainConf["registry"]; ok {
for _, services := range mainConf["registry"].(map[string]interface{}) {
for sName, nodes := range services.(map[string]interface{}) {
for _, instance := range nodes.([]interface{}) {
if err := utils.GlobalRegistry.Add(memory.NewService(sName, instance.(map[string]interface{})["nodes"].([]interface{}))); err != nil {
panic(err)
}
}
}
}
}

run(mainConf, coreConf, options.Logger, pidFile)
}

Expand All @@ -71,6 +90,7 @@ func run(mainConf map[string]interface{}, coreConf *coreConf, logger *zerolog.Lo
host, _ := os.Hostname()
logger.Info().Msgf("host info: %s", host)

// initRegistry()
initTracing(coreConf, logger)
initCPUCount(coreConf, logger)

Expand Down
11 changes: 11 additions & 0 deletions examples/ocmd/ocmd-server-1.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
[shared]
gatewaysvc = "localhost:19000"

[registry]
driver = "static"

[registry.static]
services = ["authprovider","userprovider"]

[registry.static.authprovider]
bearer = ["localhost:0123"]
basic = ["localhost:1234"]
publiclink = ["localhost:9876"]

[grpc]
address = "0.0.0.0:19000"

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ require (
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221
google.golang.org/grpc v1.37.0
google.golang.org/protobuf v1.26.0
gotest.tools v2.2.0+incompatible
)

go 1.16
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo=
gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
Expand Down
3 changes: 3 additions & 0 deletions internal/grpc/services/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ func (c *config) init() {

// if services address are not specified we used the shared conf
// for the gatewaysvc to have dev setups very quickly.

// we're commenting this line to showcase the fact that now we don't want to point to an ip address but rather
// resolve an ip address from a name.
c.AuthRegistryEndpoint = sharedconf.GetGatewaySVC(c.AuthRegistryEndpoint)
c.StorageRegistryEndpoint = sharedconf.GetGatewaySVC(c.StorageRegistryEndpoint)
c.AppRegistryEndpoint = sharedconf.GetGatewaySVC(c.AppRegistryEndpoint)
Expand Down
53 changes: 53 additions & 0 deletions pkg/registry/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2018-2021 CERN
//
// 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.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package registry

import (
"github.com/mitchellh/mapstructure"
)

// Config configures a registry
type Config struct {
Services map[string]map[string]*service `mapstructure:"services"`
}

// service implements the Service interface. Attributes are exported so that mapstructure can unmarshal values onto them.
type service struct {
Name string `mapstructure:"name"`
Nodes []node `mapstructure:"nodes"`
}

type node struct {
Address string `mapstructure:"address"`
Metadata map[string]string `mapstructure:"metadata"`
}

// ParseConfig translates Config file values into a Config struct for consumers.
func ParseConfig(m map[string]interface{}) (*Config, error) {
c := &Config{}
if err := mapstructure.Decode(m, c); err != nil {
return nil, err
}

if len(c.Services) == 0 {
c.Services = make(map[string]map[string]*service)
}

return c, nil
}
112 changes: 112 additions & 0 deletions pkg/registry/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright 2018-2021 CERN
//
// 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.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package registry

import (
"reflect"
"testing"
)

/*
config example:
---
services:
authprovider:
basic:
name: auth-basic
nodes:
- address: 0.0.0.0:1234
metadata:
version: v0.1.0
bearer:
name: auth-bearer
nodes:
- address: 0.0.0.0:5678
metadata:
version: v0.1.0
*/
func TestParseConfig(t *testing.T) {
type args struct {
m map[string]interface{}
}
tests := []struct {
name string
args args
want *Config
wantErr bool
}{
{name: "parse config", args: args{map[string]interface{}{
"services": map[string]map[string]interface{}{
"authprovider": map[string]interface{}{
"basic": map[string]interface{}{
"name": "auth-basic",
"nodes": []map[string]interface{}{
{
"address": "0.0.0.0:1234",
"metadata": map[string]string{"version": "v0.1.0"},
},
},
},
"bearer": map[string]interface{}{
"name": "auth-bearer",
"nodes": []map[string]interface{}{
{
"address": "0.0.0.0:5678",
"metadata": map[string]string{"version": "v0.1.0"},
},
},
},
},
},
}}, want: &Config{
Services: map[string]map[string]*service{
"authprovider": map[string]*service{
"basic": &service{
Name: "auth-basic",
Nodes: []node{{
Address: "0.0.0.0:1234",
Metadata: map[string]string{"version": "v0.1.0"},
}},
},
"bearer": &service{
Name: "auth-bearer",
Nodes: []node{{
Address: "0.0.0.0:5678",
Metadata: map[string]string{"version": "v0.1.0"},
}},
},
},
},
}, wantErr: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseConfig(tt.args.m)
if (err != nil) != tt.wantErr {
t.Errorf("ParseConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ParseConfig() got = %v, want %v", got, tt.want)
}
})
}
}
81 changes: 81 additions & 0 deletions pkg/registry/memory/memory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2018-2021 CERN
//
// 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.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

package memory

import (
"fmt"
"sync"

"github.com/cs3org/reva/pkg/registry"
)

// Registry implements the Registry interface.
type Registry struct {
// m protects async access to the services map.
sync.Mutex
// services map a service name with a set of nodes.
services map[string]registry.Service
}

// Add implements the Registry interface. If the service is already known in this registry it will only update the nodes.
func (r *Registry) Add(svc registry.Service) error {
r.Lock()
defer r.Unlock()

// append the nodes if the service is already registered.
if _, ok := r.services[svc.Name()]; ok {
s := service{
name: svc.Name(),
nodes: make([]node, 0),
}

s.mergeNodes(svc.Nodes(), r.services[svc.Name()].Nodes())

r.services[svc.Name()] = s
return nil
}

r.services[svc.Name()] = svc
return nil
}

// GetService implements the Registry interface. There is currently no load balance being done, but it should not be
// hard to add.
func (r *Registry) GetService(name string) (registry.Service, error) {
r.Lock()
defer r.Unlock()

if service, ok := r.services[name]; ok {
return service, nil
}

return nil, fmt.Errorf("service %v not found", name)
}

// New returns an implementation of the Registry interface.
func New(m map[string]interface{}) registry.Registry {
// c, err := registry.ParseConfig(m)
// if err != nil {
// return nil
// }

return &Registry{
services: map[string]registry.Service{},
}
}
Loading

0 comments on commit 8171b41

Please sign in to comment.