Skip to content

Commit

Permalink
feat(web_server_bin_cmd): add Web Service Binary Command Execution
Browse files Browse the repository at this point in the history
…gRPC Server

BREAKING CHANGE: the `bifrost` gRPC server APIs have added `WebServerBinCMD`.`Exec` server

The `protobuf` of the `bifrost` gRPC server APIs has been added as follows:

Protocols of addition:

```protobuf
service WebServerBinCMD {
  rpc Exec(ExecuteRequest) returns (ExecuteResponse) {}
}

message ExecuteRequest {
  string ServerName = 1;
  repeated string Args = 2;
}

message ExecuteResponse {
  bool Successful = 1;
  bytes Stdout = 2;
  bytes Stderr = 3;
}
```

The `bifrost` gRPC server APIs client SDK has been added as follows:

Methods of addition to Client Service Factory:

```go
type Factory interface {
    ...
    WebServerBinCMD() WebServerBinCMDService
}
```

Interface of addition to Client Service:

```go
type WebServerBinCMDService interface {
    Exec(servername string, arg ...string) (isSuccessful bool, stdout, stderr string, err error)
}
```
  • Loading branch information
ClessLi committed Jan 17, 2025
1 parent 8e44deb commit 8640cc6
Show file tree
Hide file tree
Showing 47 changed files with 948 additions and 133 deletions.
11 changes: 11 additions & 0 deletions api/bifrost/v1/web_server_bin_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package v1

type ExecuteRequest struct {
ServerName string `json:"server_name"`
Args []string `json:"args"`
}
type ExecuteResponse struct {
Successful bool `json:"successful"`
StandardOutput []byte `json:"stdout"`
StandardError []byte `json:"stderr"`
}
317 changes: 275 additions & 42 deletions api/protobuf-spec/bifrostpb/v1/bifrost.pb.go

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions api/protobuf-spec/bifrostpb/v1/bifrost.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ service WebServerLogWatcher {
rpc Watch(LogWatchRequest) returns (stream Response) {}
}

service WebServerBinCMD {
rpc Exec(ExecuteRequest) returns (ExecuteResponse) {}
}

message Null {}

message ServerNames {
Expand Down Expand Up @@ -52,4 +56,15 @@ message LogWatchRequest {
string ServerName = 1;
string LogName = 2;
string FilterRule =3;
}

message ExecuteRequest {
string ServerName = 1;
repeated string Args = 2;
}

message ExecuteResponse {
bool Successful = 1;
bytes Stdout = 2;
bytes Stderr = 3;
}
2 changes: 2 additions & 0 deletions docs/devel/zh-CN/scope.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
| web_server_status | bifrost 中 WebServerStatus 模块相关的变更 |
| web_server_statistics | bifrost 中 WebServerStatistics 模块相关的变更 |
| web_server_log_watcher | bifrost 中 WebServerLogWatcher 模块相关的变更 |
| web_server_bin_cmd | bifrost 中 WebServerBinCMD 模块相关的变更 |
| resolv | bifrost 中 web服务配置解析库相关的变更 |
| client | 组件gRPC客户端相关的变更 |
| pkg | pkg 包的变更 |
| docs | 文档类变更 |
Expand Down
26 changes: 14 additions & 12 deletions docs/guide/zh-CN/api/error_code_generated.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,20 @@ Bifrost 系统支持的错误码列表如下:
| ErrSameConfigFingerprints | 110003 | 500 | Same config fingerprint between files and configuration |
| ErrConfigManagerIsRunning | 110004 | 500 | Config manager is running |
| ErrConfigManagerIsNotRunning | 110005 | 500 | Config manager is not running |
| ErrConfigurationNotFound | 110006 | 400 | Web server configuration not found |
| ErrParserNotFound | 110007 | 500 | Parser not found |
| ErrUnknownKeywordString | 110008 | 500 | Unknown keyword string |
| ErrInvalidConfig | 110009 | 500 | Invalid parser.Config |
| ErrParseFailed | 110010 | 500 | Config parse failed |
| ErrV3ContextIndexOutOfRange | 110011 | 500 | Index of the Context's children is out of range |
| ErrV3NullContextPosition | 110012 | 500 | Null Context position |
| ErrV3SetFatherContextFailed | 110013 | 500 | Set father Context failed |
| ErrV3OperationOnErrorContext | 110014 | 500 | Performing operations on Error Context |
| ErrV3InvalidContext | 110015 | 500 | Invalid Context |
| ErrV3InvalidOperation | 110016 | 500 | Invalid operation |
| ErrV3ContextNotFound | 110017 | 500 | Queried context not found |
| ErrWebServerNotFound | 110006 | 400 | Web server not found |
| ErrConfigurationNotFound | 110007 | 400 | Web server configuration not found |
| ErrParserNotFound | 110008 | 500 | Parser not found |
| ErrUnknownKeywordString | 110009 | 500 | Unknown keyword string |
| ErrInvalidConfig | 110010 | 500 | Invalid parser.Config |
| ErrParseFailed | 110011 | 500 | Config parse failed |
| ErrV3ContextIndexOutOfRange | 110012 | 500 | Index of the Context's children is out of range |
| ErrV3NullContextPosition | 110013 | 500 | Null Context position |
| ErrV3SetFatherContextFailed | 110014 | 500 | Set father Context failed |
| ErrV3OperationOnErrorContext | 110015 | 500 | Performing operations on Error Context |
| ErrV3InvalidContext | 110016 | 500 | Invalid Context |
| ErrV3InvalidOperation | 110017 | 500 | Invalid operation |
| ErrV3ContextNotFound | 110018 | 500 | Queried context not found |
| ErrV3ConversionToContextFailed | 110019 | 500 | Conversion to context failed |
| ErrStopMonitoringTimeout | 110201 | 500 | Stop monitoring timeout |
| ErrMonitoringServiceSuspension | 110202 | 500 | Monitoring service suspension |
| ErrMonitoringStarted | 110203 | 500 | Monitoring is already started |
Expand Down
6 changes: 6 additions & 0 deletions internal/bifrost/endpoint/v1/endpoints.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1

import (
"github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1/web_server_bin_cmd"
"github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1/web_server_config"
"github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1/web_server_log_watcher"
"github.com/ClessLi/bifrost/internal/bifrost/endpoint/v1/web_server_statistics"
Expand All @@ -13,6 +14,7 @@ type EndpointsFactory interface {
WebServerStatistics() WebServerStatisticsEndpoints
WebServerStatus() WebServerStatusEndpoints
WebServerLogWatcher() WebServerLogWatcherEndpoints
WebServerBinCMD() WebServerBinCMDEndpoints
}

var _ EndpointsFactory = &endpoints{}
Expand Down Expand Up @@ -40,3 +42,7 @@ func (e *endpoints) WebServerStatus() WebServerStatusEndpoints {
func (e *endpoints) WebServerLogWatcher() WebServerLogWatcherEndpoints {
return web_server_log_watcher.NewWebServerLogWatcherEndpoints(e.svc)
}

func (e *endpoints) WebServerBinCMD() WebServerBinCMDEndpoints {
return web_server_bin_cmd.NewWebServerBinCMDEndpoints(e.svc)
}
7 changes: 7 additions & 0 deletions internal/bifrost/endpoint/v1/web_server_bin_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package v1

import "github.com/go-kit/kit/endpoint"

type WebServerBinCMDEndpoints interface {
EndpointExec() endpoint.Endpoint
}
19 changes: 19 additions & 0 deletions internal/bifrost/endpoint/v1/web_server_bin_cmd/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package web_server_bin_cmd

import (
"context"
v1 "github.com/ClessLi/bifrost/api/bifrost/v1"

"github.com/go-kit/kit/endpoint"
"github.com/marmotedu/errors"
)

func (w *webServerBinCMDEndpoints) EndpointExec() endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
if req, ok := request.(*v1.ExecuteRequest); ok {
return w.svc.WebServerBinCMD().Exec(ctx, req)
}

return nil, errors.Errorf("invalid get request, need *pbv1.ExecuteRequest, not %T", request)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package web_server_bin_cmd

import svcv1 "github.com/ClessLi/bifrost/internal/bifrost/service/v1"

type webServerBinCMDEndpoints struct {
svc svcv1.ServiceFactory
}

func NewWebServerBinCMDEndpoints(svc svcv1.ServiceFactory) *webServerBinCMDEndpoints {
return &webServerBinCMDEndpoints{svc: svc}
}
4 changes: 4 additions & 0 deletions internal/bifrost/middleware/logging/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ func (l *loggingService) WebServerLogWatcher() svcv1.WebServerLogWatcherService
return newWebServerLogWatcherMiddleware(l.svc)
}

func (l *loggingService) WebServerBinCMD() svcv1.WebServerBinCMDService {
return newWebServerBinCMDMiddleware(l.svc)
}

func New(svc svcv1.ServiceFactory) svcv1.ServiceFactory {
once.Do(func() {
logger = logV1.K()
Expand Down
33 changes: 33 additions & 0 deletions internal/bifrost/middleware/logging/web_server_bin_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package logging

import (
"context"
"encoding/json"
"time"

v1 "github.com/ClessLi/bifrost/api/bifrost/v1"
svcv1 "github.com/ClessLi/bifrost/internal/bifrost/service/v1"
)

type loggingWebServerBinCMDService struct {
svc svcv1.WebServerBinCMDService
}

func (l *loggingWebServerBinCMDService) Exec(ctx context.Context, request *v1.ExecuteRequest) (response *v1.ExecuteResponse, err error) {
defer func(begin time.Time) {
logF := newLogFormatter(ctx, l.svc.Exec)
logF.SetBeginTime(begin)
defer logF.Result()
if response != nil {
result, _ := json.Marshal(response)
logF.SetResult(getLimitResult(result))
}
logF.SetErr(err)
}(time.Now().Local())

return l.svc.Exec(ctx, request)
}

func newWebServerBinCMDMiddleware(svc svcv1.ServiceFactory) svcv1.WebServerBinCMDService {
return &loggingWebServerBinCMDService{svc: svc.WebServerBinCMD()}
}
6 changes: 6 additions & 0 deletions internal/bifrost/service/v1/service.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1

import (
"github.com/ClessLi/bifrost/internal/bifrost/service/v1/web_server_bin_cmd"
"github.com/ClessLi/bifrost/internal/bifrost/service/v1/web_server_config"
"github.com/ClessLi/bifrost/internal/bifrost/service/v1/web_server_log_watcher"
"github.com/ClessLi/bifrost/internal/bifrost/service/v1/web_server_statistics"
Expand All @@ -13,6 +14,7 @@ type ServiceFactory interface {
WebServerStatistics() WebServerStatisticsService
WebServerStatus() WebServerStatusService
WebServerLogWatcher() WebServerLogWatcherService
WebServerBinCMD() WebServerBinCMDService
}

var _ ServiceFactory = &serviceFactory{}
Expand All @@ -37,6 +39,10 @@ func (s *serviceFactory) WebServerLogWatcher() WebServerLogWatcherService {
return web_server_log_watcher.NewWebServerLogWatcherService(s.store)
}

func (s *serviceFactory) WebServerBinCMD() WebServerBinCMDService {
return web_server_bin_cmd.NewWebServerBinCMDService(s.store)
}

func NewServiceFactory(store storev1.StoreFactory) ServiceFactory {
return &serviceFactory{store: store}
}
11 changes: 11 additions & 0 deletions internal/bifrost/service/v1/web_server_bin_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package v1

import (
"context"

v1 "github.com/ClessLi/bifrost/api/bifrost/v1"
)

type WebServerBinCMDService interface {
Exec(ctx context.Context, request *v1.ExecuteRequest) (*v1.ExecuteResponse, error)
}
11 changes: 11 additions & 0 deletions internal/bifrost/service/v1/web_server_bin_cmd/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package web_server_bin_cmd

import (
"context"

v1 "github.com/ClessLi/bifrost/api/bifrost/v1"
)

func (w *webServerBinCMDService) Exec(ctx context.Context, req *v1.ExecuteRequest) (*v1.ExecuteResponse, error) {
return w.store.WebServerBinCMD().Exec(ctx, req)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package web_server_bin_cmd

import storev1 "github.com/ClessLi/bifrost/internal/bifrost/store/v1"

type webServerBinCMDService struct {
store storev1.StoreFactory
}

func NewWebServerBinCMDService(store storev1.StoreFactory) *webServerBinCMDService {
return &webServerBinCMDService{store: store}
}
6 changes: 5 additions & 1 deletion internal/bifrost/store/v1/nginx/nginx.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ func (w *webServerStore) WebServerStatistics() storev1.WebServerStatisticsStore
return newNginxStatisticsStore(w)
}

func (w *webServerStore) WebServerLogWatcher() storev1.WebServerLogWatcher {
func (w *webServerStore) WebServerLogWatcher() storev1.WebServerLogWatcherStore {
return newWebServerLogWatcherStore(w)
}

func (w *webServerStore) WebServerBinCMD() storev1.WebServerBinCMDStore {
return newNginxBinCMDStore(w)
}

func (w *webServerStore) Close() error {
return errors.NewAggregate([]error{
w.configsManger.Stop(5 * time.Minute),
Expand Down
41 changes: 41 additions & 0 deletions internal/bifrost/store/v1/nginx/web_server_bin_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package nginx

import (
"bytes"
"context"
v1 "github.com/ClessLi/bifrost/api/bifrost/v1"
storev1 "github.com/ClessLi/bifrost/internal/bifrost/store/v1"
"github.com/ClessLi/bifrost/internal/pkg/code"
"github.com/marmotedu/errors"
"os/exec"
)

type webServerBinCMDStore struct {
serversBinCMD map[string]func(arg ...string) *exec.Cmd
}

func (w webServerBinCMDStore) Exec(ctx context.Context, request *v1.ExecuteRequest) (*v1.ExecuteResponse, error) {
if f, has := w.serversBinCMD[request.ServerName]; has {
cmd := f(request.Args...)

var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr

var isSuccessful = cmd.Run() == nil

return &v1.ExecuteResponse{
Successful: isSuccessful,
StandardOutput: stdout.Bytes(),
StandardError: stderr.Bytes(),
}, nil
}

return nil, errors.WithCode(code.ErrWebServerNotFound, "nginx server '%s' not found", request.ServerName)
}

var _ storev1.WebServerBinCMDStore = &webServerBinCMDStore{}

func newNginxBinCMDStore(store *webServerStore) storev1.WebServerBinCMDStore {
return &webServerBinCMDStore{serversBinCMD: store.configsManger.GetServersBinCMD()}
}
3 changes: 2 additions & 1 deletion internal/bifrost/store/v1/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ type StoreFactory interface {
WebServerConfig() WebServerConfigStore
WebServerStatistics() WebServerStatisticsStore
WebServerStatus() WebServerStatusStore
WebServerLogWatcher() WebServerLogWatcher
WebServerLogWatcher() WebServerLogWatcherStore
WebServerBinCMD() WebServerBinCMDStore
Close() error
}

Expand Down
11 changes: 11 additions & 0 deletions internal/bifrost/store/v1/web_server_bin_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package v1

import (
"context"

v1 "github.com/ClessLi/bifrost/api/bifrost/v1"
)

type WebServerBinCMDStore interface {
Exec(ctx context.Context, request *v1.ExecuteRequest) (*v1.ExecuteResponse, error)
}
2 changes: 1 addition & 1 deletion internal/bifrost/store/v1/web_server_log_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import (
v1 "github.com/ClessLi/bifrost/api/bifrost/v1"
)

type WebServerLogWatcher interface {
type WebServerLogWatcherStore interface {
Watch(ctx context.Context, request *v1.WebServerLogWatchRequest) (*v1.WebServerLog, error)
}
31 changes: 31 additions & 0 deletions internal/bifrost/transport/v1/decoder/web_server_bin_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package decoder

import (
"context"
v1 "github.com/ClessLi/bifrost/api/bifrost/v1"

"github.com/marmotedu/errors"

pbv1 "github.com/ClessLi/bifrost/api/protobuf-spec/bifrostpb/v1"
"github.com/ClessLi/bifrost/internal/pkg/code"
)

type webServerBinCMD struct{}

var _ Decoder = webServerBinCMD{}

func (w webServerBinCMD) DecodeRequest(ctx context.Context, r interface{}) (interface{}, error) {
switch r := r.(type) {
case *pbv1.ExecuteRequest:
return &v1.ExecuteRequest{
ServerName: r.ServerName,
Args: r.Args,
}, nil
default:
return nil, errors.WithCode(code.ErrDecodingFailed, "invalid execute request: %v", r)
}
}

func NewWebServerBinCMDDecoder() Decoder {
return new(webServerBinCMD)
}
Loading

0 comments on commit 8640cc6

Please sign in to comment.