2019-11-20 14:54:42 +00:00
|
|
|
package service
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-07-13 17:35:23 +01:00
|
|
|
"io"
|
2019-11-20 14:54:42 +00:00
|
|
|
"sync"
|
|
|
|
|
2020-01-30 14:39:00 +03:00
|
|
|
"github.com/micro/go-micro/v2/client"
|
|
|
|
"github.com/micro/go-micro/v2/runtime"
|
|
|
|
pb "github.com/micro/go-micro/v2/runtime/service/proto"
|
2019-11-20 14:54:42 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type svc struct {
|
|
|
|
sync.RWMutex
|
|
|
|
options runtime.Options
|
|
|
|
runtime pb.RuntimeService
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init initializes runtime with given options
|
|
|
|
func (s *svc) Init(opts ...runtime.Option) error {
|
|
|
|
s.Lock()
|
|
|
|
defer s.Unlock()
|
|
|
|
|
|
|
|
for _, o := range opts {
|
|
|
|
o(&s.options)
|
|
|
|
}
|
|
|
|
|
2020-05-11 17:09:28 +01:00
|
|
|
// reset the runtime as the client could have changed
|
|
|
|
s.runtime = pb.NewRuntimeService(runtime.DefaultName, s.options.Client)
|
|
|
|
|
2019-11-20 14:54:42 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create registers a service in the runtime
|
|
|
|
func (s *svc) Create(svc *runtime.Service, opts ...runtime.CreateOption) error {
|
2020-04-23 13:53:42 +01:00
|
|
|
var options runtime.CreateOptions
|
2019-11-20 14:54:42 +00:00
|
|
|
for _, o := range opts {
|
|
|
|
o(&options)
|
|
|
|
}
|
2020-04-23 13:53:42 +01:00
|
|
|
if options.Context == nil {
|
|
|
|
options.Context = context.Background()
|
|
|
|
}
|
2019-11-20 14:54:42 +00:00
|
|
|
|
2020-02-24 17:47:47 +00:00
|
|
|
// set the default source from MICRO_RUNTIME_SOURCE
|
|
|
|
if len(svc.Source) == 0 {
|
|
|
|
svc.Source = s.options.Source
|
|
|
|
}
|
|
|
|
|
2019-11-20 14:54:42 +00:00
|
|
|
// runtime service create request
|
|
|
|
req := &pb.CreateRequest{
|
|
|
|
Service: &pb.Service{
|
2019-11-22 17:10:00 +00:00
|
|
|
Name: svc.Name,
|
|
|
|
Version: svc.Version,
|
|
|
|
Source: svc.Source,
|
|
|
|
Metadata: svc.Metadata,
|
2019-11-20 14:54:42 +00:00
|
|
|
},
|
|
|
|
Options: &pb.CreateOptions{
|
2020-07-03 11:37:14 +01:00
|
|
|
Command: options.Command,
|
|
|
|
Args: options.Args,
|
|
|
|
Env: options.Env,
|
|
|
|
Type: options.Type,
|
|
|
|
Image: options.Image,
|
|
|
|
Namespace: options.Namespace,
|
2019-11-20 14:54:42 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-04-23 13:53:42 +01:00
|
|
|
if _, err := s.runtime.Create(options.Context, req); err != nil {
|
2019-11-20 14:54:42 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-04-23 13:53:42 +01:00
|
|
|
func (s *svc) Logs(service *runtime.Service, opts ...runtime.LogsOption) (runtime.LogStream, error) {
|
|
|
|
var options runtime.LogsOptions
|
|
|
|
for _, o := range opts {
|
|
|
|
o(&options)
|
|
|
|
}
|
2020-04-28 09:49:39 +02:00
|
|
|
|
2020-04-23 13:53:42 +01:00
|
|
|
if options.Context == nil {
|
|
|
|
options.Context = context.Background()
|
|
|
|
}
|
|
|
|
|
|
|
|
ls, err := s.runtime.Logs(options.Context, &pb.LogsRequest{
|
2020-04-01 15:40:15 +02:00
|
|
|
Service: service.Name,
|
2020-04-28 09:49:39 +02:00
|
|
|
Stream: options.Stream,
|
|
|
|
Count: options.Count,
|
2020-07-03 11:37:14 +01:00
|
|
|
Options: &pb.LogsOptions{
|
|
|
|
Namespace: options.Namespace,
|
|
|
|
},
|
2020-04-01 15:40:15 +02:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
logStream := &serviceLogStream{
|
|
|
|
service: service.Name,
|
|
|
|
stream: make(chan runtime.LogRecord),
|
|
|
|
stop: make(chan bool),
|
|
|
|
}
|
2020-04-28 09:49:39 +02:00
|
|
|
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
// @todo this never seems to return, investigate
|
|
|
|
case <-ls.Context().Done():
|
|
|
|
logStream.Stop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
2020-04-01 15:40:15 +02:00
|
|
|
go func() {
|
|
|
|
for {
|
2020-04-28 09:49:39 +02:00
|
|
|
select {
|
|
|
|
// @todo this never seems to return, investigate
|
|
|
|
case <-ls.Context().Done():
|
|
|
|
return
|
|
|
|
case _, ok := <-logStream.stream:
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
record := pb.LogRecord{}
|
|
|
|
err := ls.RecvMsg(&record)
|
|
|
|
if err != nil {
|
2020-07-13 17:35:23 +01:00
|
|
|
if err != io.EOF {
|
|
|
|
logStream.err = err
|
|
|
|
}
|
2020-04-28 09:49:39 +02:00
|
|
|
logStream.Stop()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
logStream.stream <- runtime.LogRecord{
|
|
|
|
Message: record.GetMessage(),
|
|
|
|
Metadata: record.GetMetadata(),
|
|
|
|
}
|
2020-04-01 15:40:15 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return logStream, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type serviceLogStream struct {
|
|
|
|
service string
|
|
|
|
stream chan runtime.LogRecord
|
2020-04-02 13:16:35 +02:00
|
|
|
sync.Mutex
|
|
|
|
stop chan bool
|
|
|
|
err error
|
2020-04-02 00:03:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (l *serviceLogStream) Error() error {
|
|
|
|
return l.err
|
2020-04-01 15:40:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (l *serviceLogStream) Chan() chan runtime.LogRecord {
|
|
|
|
return l.stream
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *serviceLogStream) Stop() error {
|
2020-04-02 13:16:35 +02:00
|
|
|
l.Lock()
|
|
|
|
defer l.Unlock()
|
2020-04-01 15:40:15 +02:00
|
|
|
select {
|
|
|
|
case <-l.stop:
|
|
|
|
return nil
|
|
|
|
default:
|
2020-04-28 09:49:39 +02:00
|
|
|
close(l.stream)
|
2020-04-01 15:40:15 +02:00
|
|
|
close(l.stop)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-11-25 16:31:14 +00:00
|
|
|
// Read returns the service with the given name from the runtime
|
2019-11-29 11:35:00 +00:00
|
|
|
func (s *svc) Read(opts ...runtime.ReadOption) ([]*runtime.Service, error) {
|
2020-04-23 13:53:42 +01:00
|
|
|
var options runtime.ReadOptions
|
2019-11-20 14:54:42 +00:00
|
|
|
for _, o := range opts {
|
|
|
|
o(&options)
|
|
|
|
}
|
2020-04-23 13:53:42 +01:00
|
|
|
if options.Context == nil {
|
|
|
|
options.Context = context.Background()
|
|
|
|
}
|
2019-11-20 14:54:42 +00:00
|
|
|
|
|
|
|
// runtime service create request
|
2019-11-25 16:31:14 +00:00
|
|
|
req := &pb.ReadRequest{
|
|
|
|
Options: &pb.ReadOptions{
|
2020-07-03 11:37:14 +01:00
|
|
|
Service: options.Service,
|
|
|
|
Version: options.Version,
|
|
|
|
Type: options.Type,
|
|
|
|
Namespace: options.Namespace,
|
2019-11-20 14:54:42 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-04-23 13:53:42 +01:00
|
|
|
resp, err := s.runtime.Read(options.Context, req)
|
2019-11-20 14:54:42 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
services := make([]*runtime.Service, 0, len(resp.Services))
|
|
|
|
for _, service := range resp.Services {
|
|
|
|
svc := &runtime.Service{
|
2019-11-22 17:10:00 +00:00
|
|
|
Name: service.Name,
|
|
|
|
Version: service.Version,
|
|
|
|
Source: service.Source,
|
|
|
|
Metadata: service.Metadata,
|
2019-11-20 14:54:42 +00:00
|
|
|
}
|
|
|
|
services = append(services, svc)
|
|
|
|
}
|
|
|
|
|
|
|
|
return services, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update updates the running service
|
2020-04-23 13:53:42 +01:00
|
|
|
func (s *svc) Update(svc *runtime.Service, opts ...runtime.UpdateOption) error {
|
|
|
|
var options runtime.UpdateOptions
|
|
|
|
for _, o := range opts {
|
|
|
|
o(&options)
|
|
|
|
}
|
|
|
|
if options.Context == nil {
|
|
|
|
options.Context = context.Background()
|
|
|
|
}
|
|
|
|
|
2019-11-20 14:54:42 +00:00
|
|
|
// runtime service create request
|
|
|
|
req := &pb.UpdateRequest{
|
|
|
|
Service: &pb.Service{
|
2020-03-27 11:37:12 +00:00
|
|
|
Name: svc.Name,
|
|
|
|
Version: svc.Version,
|
|
|
|
Source: svc.Source,
|
|
|
|
Metadata: svc.Metadata,
|
2019-11-20 14:54:42 +00:00
|
|
|
},
|
2020-07-03 11:37:14 +01:00
|
|
|
Options: &pb.UpdateOptions{
|
|
|
|
Namespace: options.Namespace,
|
|
|
|
},
|
2019-11-20 14:54:42 +00:00
|
|
|
}
|
|
|
|
|
2020-04-23 13:53:42 +01:00
|
|
|
if _, err := s.runtime.Update(options.Context, req); err != nil {
|
2019-11-20 14:54:42 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete stops and removes the service from the runtime
|
2020-04-23 13:53:42 +01:00
|
|
|
func (s *svc) Delete(svc *runtime.Service, opts ...runtime.DeleteOption) error {
|
|
|
|
var options runtime.DeleteOptions
|
|
|
|
for _, o := range opts {
|
|
|
|
o(&options)
|
|
|
|
}
|
|
|
|
if options.Context == nil {
|
|
|
|
options.Context = context.Background()
|
|
|
|
}
|
|
|
|
|
2019-11-20 14:54:42 +00:00
|
|
|
// runtime service create request
|
|
|
|
req := &pb.DeleteRequest{
|
|
|
|
Service: &pb.Service{
|
2020-03-27 11:37:12 +00:00
|
|
|
Name: svc.Name,
|
|
|
|
Version: svc.Version,
|
|
|
|
Source: svc.Source,
|
|
|
|
Metadata: svc.Metadata,
|
2019-11-20 14:54:42 +00:00
|
|
|
},
|
2020-07-03 11:37:14 +01:00
|
|
|
Options: &pb.DeleteOptions{
|
|
|
|
Namespace: options.Namespace,
|
|
|
|
},
|
2019-11-20 14:54:42 +00:00
|
|
|
}
|
|
|
|
|
2020-04-23 13:53:42 +01:00
|
|
|
if _, err := s.runtime.Delete(options.Context, req); err != nil {
|
2019-11-20 14:54:42 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start starts the runtime
|
|
|
|
func (s *svc) Start() error {
|
|
|
|
// NOTE: nothing to be done here
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop stops the runtime
|
|
|
|
func (s *svc) Stop() error {
|
|
|
|
// NOTE: nothing to be done here
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the runtime service implementation
|
|
|
|
func (s *svc) String() string {
|
|
|
|
return "service"
|
|
|
|
}
|
2020-01-19 00:55:01 +00:00
|
|
|
|
|
|
|
// NewRuntime creates new service runtime and returns it
|
|
|
|
func NewRuntime(opts ...runtime.Option) runtime.Runtime {
|
2020-05-11 17:09:28 +01:00
|
|
|
var options runtime.Options
|
2020-01-19 00:55:01 +00:00
|
|
|
|
|
|
|
for _, o := range opts {
|
|
|
|
o(&options)
|
|
|
|
}
|
2020-05-11 17:09:28 +01:00
|
|
|
if options.Client == nil {
|
|
|
|
options.Client = client.DefaultClient
|
|
|
|
}
|
2020-01-19 00:55:01 +00:00
|
|
|
|
|
|
|
return &svc{
|
|
|
|
options: options,
|
2020-05-11 17:09:28 +01:00
|
|
|
runtime: pb.NewRuntimeService(runtime.DefaultName, options.Client),
|
2020-01-19 00:55:01 +00:00
|
|
|
}
|
|
|
|
}
|