diff --git a/registry/service/options.go b/registry/service/options.go new file mode 100644 index 00000000..fd251d77 --- /dev/null +++ b/registry/service/options.go @@ -0,0 +1,21 @@ +package service + +import ( + "context" + + "github.com/micro/go-micro/v2/client" + "github.com/micro/go-micro/v2/registry" +) + +type clientKey struct{} + +// WithClient sets the RPC client +func WithClient(c client.Client) registry.Option { + return func(o *registry.Options) { + if o.Context == nil { + o.Context = context.Background() + } + + o.Context = context.WithValue(o.Context, clientKey{}, c) + } +} diff --git a/registry/service/service.go b/registry/service/service.go index acf42d3a..9e2829f4 100644 --- a/registry/service/service.go +++ b/registry/service/service.go @@ -22,8 +22,8 @@ type serviceRegistry struct { name string // address address []string - // client to call registry - client pb.RegistryService + // registry is the proto client + registry pb.RegistryService } func (s *serviceRegistry) callOpts() []client.CallOption { @@ -46,6 +46,17 @@ func (s *serviceRegistry) Init(opts ...registry.Option) error { for _, o := range opts { o(&s.opts) } + + // extract the client from the context, fallback to grpc + var cli client.Client + if c, ok := s.opts.Context.Value(clientKey{}).(client.Client); ok { + cli = c + } else { + cli = grpc.NewClient() + } + + s.registry = pb.NewRegistryService(DefaultService, cli) + return nil } @@ -67,7 +78,7 @@ func (s *serviceRegistry) Register(srv *registry.Service, opts ...registry.Regis pbSrv.Options.Ttl = int64(options.TTL.Seconds()) // register the service - _, err := s.client.Register(options.Context, pbSrv, s.callOpts()...) + _, err := s.registry.Register(options.Context, pbSrv, s.callOpts()...) if err != nil { return err } @@ -85,7 +96,7 @@ func (s *serviceRegistry) Deregister(srv *registry.Service, opts ...registry.Der } // deregister the service - _, err := s.client.Deregister(options.Context, ToProto(srv), s.callOpts()...) + _, err := s.registry.Deregister(options.Context, ToProto(srv), s.callOpts()...) if err != nil { return err } @@ -101,7 +112,7 @@ func (s *serviceRegistry) GetService(name string, opts ...registry.GetOption) ([ options.Context = context.TODO() } - rsp, err := s.client.GetService(options.Context, &pb.GetRequest{ + rsp, err := s.registry.GetService(options.Context, &pb.GetRequest{ Service: name, }, s.callOpts()...) @@ -125,7 +136,7 @@ func (s *serviceRegistry) ListServices(opts ...registry.ListOption) ([]*registry options.Context = context.TODO() } - rsp, err := s.client.ListServices(options.Context, &pb.ListRequest{}, s.callOpts()...) + rsp, err := s.registry.ListServices(options.Context, &pb.ListRequest{}, s.callOpts()...) if err != nil { return nil, err } @@ -147,7 +158,7 @@ func (s *serviceRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, options.Context = context.TODO() } - stream, err := s.client.Watch(options.Context, &pb.WatchRequest{ + stream, err := s.registry.Watch(options.Context, &pb.WatchRequest{ Service: options.Service, }, s.callOpts()...) @@ -171,27 +182,29 @@ func NewRegistry(opts ...registry.Option) registry.Registry { // the registry address addrs := options.Addrs - if len(addrs) == 0 { addrs = []string{"127.0.0.1:8000"} } - // use mdns as a fall back in case its used - mReg := registry.NewRegistry() + if options.Context == nil { + options.Context = context.TODO() + } - // create new client with mdns - cli := grpc.NewClient( - client.Registry(mReg), - ) + // extract the client from the context, fallback to grpc + var cli client.Client + if c, ok := options.Context.Value(clientKey{}).(client.Client); ok { + cli = c + } else { + cli = grpc.NewClient() + } - // service name - // TODO: accept option + // service name. TODO: accept option name := DefaultService return &serviceRegistry{ - opts: options, - name: name, - address: addrs, - client: pb.NewRegistryService(name, cli), + opts: options, + name: name, + address: addrs, + registry: pb.NewRegistryService(name, cli), } } diff --git a/service.go b/service.go index 00967ea6..2a330870 100644 --- a/service.go +++ b/service.go @@ -1,6 +1,7 @@ package micro import ( + "fmt" "os" "os/signal" rtime "runtime" @@ -15,6 +16,7 @@ import ( "github.com/micro/go-micro/v2/debug/trace" "github.com/micro/go-micro/v2/logger" "github.com/micro/go-micro/v2/plugin" + srvRegistry "github.com/micro/go-micro/v2/registry/service" "github.com/micro/go-micro/v2/runtime" "github.com/micro/go-micro/v2/server" "github.com/micro/go-micro/v2/store" @@ -115,7 +117,8 @@ func (s *service) Init(opts ...Option) { s.opts.Store.Init(store.Table(name)) // Set the client for the micro clients - // s.opts.Auth.Init(auth.WithClient(s.Client())) + s.opts.Auth.Init(auth.WithClient(s.Client())) + s.opts.Registry.Init(srvRegistry.WithClient(s.Client())) s.opts.Runtime.Init(runtime.WithClient(s.Client())) s.opts.Store.Init(store.WithClient(s.Client())) }) @@ -205,6 +208,11 @@ func (s *service) Run() error { logger.Infof("Starting [service] %s", s.Name()) } + // generate an auth account + if err := s.registerAuthAccount(); err != nil { + return err + } + if err := s.Start(); err != nil { return err } @@ -223,3 +231,37 @@ func (s *service) Run() error { return s.Stop() } + +func (s *service) registerAuthAccount() error { + // determine the type of service from the name. we do this so we can allocate + // different roles depending on the type of services. e.g. we don't want web + // services talking directly to the runtime. TODO: find a better way to determine + // the type of service + serviceType := "service" + if strings.Contains(s.Name(), "api") { + serviceType = "api" + } else if strings.Contains(s.Name(), "web") { + serviceType = "web" + } + + // generate a new auth account for the service + name := fmt.Sprintf("%v-%v", s.Name(), s.Server().Options().Id) + opts := []auth.GenerateOption{ + auth.WithRoles(serviceType), + auth.WithNamespace(s.Options().Auth.Options().Namespace), + } + acc, err := s.Options().Auth.Generate(name, opts...) + if err != nil { + return err + } + + // generate a token + token, err := s.Options().Auth.Token(auth.WithCredentials(acc.ID, acc.Secret)) + if err != nil { + return err + } + s.Options().Auth.Init(auth.ClientToken(token)) + + logger.Infof("Auth [%v] Authenticated as %v", s.Options().Auth, name) + return nil +} diff --git a/util/wrapper/wrapper.go b/util/wrapper/wrapper.go index dba8d274..8dde56f0 100644 --- a/util/wrapper/wrapper.go +++ b/util/wrapper/wrapper.go @@ -2,7 +2,6 @@ package wrapper import ( "context" - "fmt" "strings" "time" @@ -182,47 +181,14 @@ func (a *authWrapper) Call(ctx context.Context, req client.Request, rsp interfac return callWithToken(tok.AccessToken) } - // if we have credentials we can generate a new token for the account - if len(aaOpts.ID) > 0 && len(aaOpts.Secret) > 0 { - tok, err := aa.Token(auth.WithCredentials(aaOpts.ID, aaOpts.Secret)) - if err != nil { - return err - } - aa.Init(auth.ClientToken(tok)) - return callWithToken(tok.AccessToken) - } - // check to see if a token was provided in config, this is normally used for // setting the token when calling via the cli if token, err := config.Get("micro", "auth", "token"); err == nil && len(token) > 0 { return callWithToken(token) } - // determine the type of service from the name. we do this so we can allocate - // different roles depending on the type of services. e.g. we don't want web - // services talking directly to the runtime. TODO: find a better way to determine - // the type of service - serviceType := "service" - if strings.Contains(a.name, "api") { - serviceType = "api" - } else if strings.Contains(a.name, "web") { - serviceType = "web" - } - - // generate a new auth account for the service - name := fmt.Sprintf("%v-%v", a.name, a.id) - acc, err := aa.Generate(name, auth.WithNamespace(aaOpts.Namespace), auth.WithRoles(serviceType)) - if err != nil { - return err - } - token, err := aa.Token(auth.WithCredentials(acc.ID, acc.Secret)) - if err != nil { - return err - } - aa.Init(auth.ClientToken(token)) - - // use the token to execute the request - return callWithToken(token.AccessToken) + // call without an auth token + return a.Client.Call(ctx, req, rsp, opts...) } // AuthClient wraps requests with the auth header