From 54c6556f2d0e69890e833eec4f604aaa29f95d29 Mon Sep 17 00:00:00 2001 From: Dean Coakley Date: Tue, 22 Nov 2022 16:14:46 +0000 Subject: [PATCH 1/8] WIP: Add nginx config update rest api --- src/core/nginx.go | 2 +- src/core/topics.go | 1 + src/plugins/agent_api.go | 144 ++++++++++++++++-- src/plugins/agent_api_test.go | 65 +++++++- src/plugins/nginx.go | 132 +++++++++++----- src/plugins/nginx_test.go | 16 +- .../nginx/agent/v2/src/core/nginx.go | 2 +- .../nginx/agent/v2/src/core/topics.go | 1 + .../nginx/agent/v2/src/plugins/agent_api.go | 144 ++++++++++++++++-- .../nginx/agent/v2/src/plugins/nginx.go | 132 +++++++++++----- 10 files changed, 534 insertions(+), 105 deletions(-) diff --git a/src/core/nginx.go b/src/core/nginx.go index 164a89302..ff36d93bc 100644 --- a/src/core/nginx.go +++ b/src/core/nginx.go @@ -341,7 +341,7 @@ func (n *NginxBinaryType) WriteConfig(config *proto.NginxConfig) (*sdk.ConfigApp } // Ensure all aux files are within the allowed list directories. - if err := ensureFilesAllowed(auxFiles, n.config.AllowedDirectoriesMap, config.Zaux.RootDirectory); err != nil { + if err := ensureFilesAllowed(auxFiles, n.config.AllowedDirectoriesMap, config.GetZaux().GetRootDirectory()); err != nil { return nil, err } diff --git a/src/core/topics.go b/src/core/topics.go index 41dc95b57..022550740 100644 --- a/src/core/topics.go +++ b/src/core/topics.go @@ -45,4 +45,5 @@ const ( ConfigRollbackResponse = "config.rollback.response" DataplaneSoftwareDetailsUpdated = "dataplane.software.details.updated" EnableExtension = "enable.extension" + RestAPIConfigApplyResponse = "rest.api.config.apply.response" ) diff --git a/src/plugins/agent_api.go b/src/plugins/agent_api.go index 5bb369be2..8b444492e 100644 --- a/src/plugins/agent_api.go +++ b/src/plugins/agent_api.go @@ -5,9 +5,12 @@ import ( "context" "encoding/json" "fmt" + "io" "net/http" "regexp" + "time" + "github.com/nginx/agent/sdk/v2" "github.com/nginx/agent/sdk/v2/proto" "github.com/nginx/agent/v2/src/core" "github.com/nginx/agent/v2/src/core/config" @@ -18,22 +21,31 @@ import ( type AgentAPI struct { config *config.Config env core.Environment + pipeline core.MessagePipeInterface server http.Server nginxBinary core.NginxBinary nginxHandler *NginxHandler } type NginxHandler struct { - env core.Environment - nginxBinary core.NginxBinary + config *config.Config + env core.Environment + pipeline core.MessagePipeInterface + nginxBinary core.NginxBinary + responseChannel chan *proto.Command_NginxConfigResponse } func NewAgentAPI(config *config.Config, env core.Environment, nginxBinary core.NginxBinary) *AgentAPI { - return &AgentAPI{config: config, env: env, nginxBinary: nginxBinary} + return &AgentAPI{ + config: config, + env: env, + nginxBinary: nginxBinary, + } } -func (a *AgentAPI) Init(core.MessagePipeInterface) { +func (a *AgentAPI) Init(pipeline core.MessagePipeInterface) { log.Info("Agent API initializing") + a.pipeline = pipeline go a.createHttpServer() } @@ -46,6 +58,16 @@ func (a *AgentAPI) Close() { func (a *AgentAPI) Process(message *core.Message) { log.Tracef("Process function in the agent_api.go, %s %v", message.Topic(), message.Data()) + + switch message.Topic() { + case core.RestAPIConfigApplyResponse: + switch response := message.Data().(type) { + case *proto.Command_NginxConfigResponse: + a.nginxHandler.responseChannel <- response + default: + log.Warnf("Unknown Command_NginxConfigResponse type: %T(%v)", message.Data(), message.Data()) + } + } } func (a *AgentAPI) Info() *core.Info { @@ -53,21 +75,28 @@ func (a *AgentAPI) Info() *core.Info { } func (a *AgentAPI) Subscriptions() []string { - return []string{} + return []string{core.RestAPIConfigApplyResponse} } func (a *AgentAPI) createHttpServer() { + a.nginxHandler = &NginxHandler{ + config: a.config, + pipeline: a.pipeline, + env: a.env, + nginxBinary: a.nginxBinary, + responseChannel: make(chan *proto.Command_NginxConfigResponse), + } + mux := http.NewServeMux() - a.nginxHandler = &NginxHandler{a.env, a.nginxBinary} mux.Handle("/nginx/", a.nginxHandler) - log.Debug("Starting Agent API HTTP server") - a.server = http.Server{ Addr: fmt.Sprintf(":%d", a.config.AgentAPI.Port), Handler: mux, } + log.Debug("Starting Agent API HTTP server") + if err := a.server.ListenAndServe(); err != http.ErrServerClosed { log.Fatalf("error listening to port: %v", err) } @@ -75,16 +104,32 @@ func (a *AgentAPI) createHttpServer() { var ( instancesRegex = regexp.MustCompile(`^\/nginx[\/]*$`) + configRegex = regexp.MustCompile(`^\/nginx/config[\/]*$`) ) func (h *NginxHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") switch { - case r.Method == http.MethodGet && instancesRegex.MatchString(r.URL.Path): + case instancesRegex.MatchString(r.URL.Path): + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + err := sendInstanceDetailsPayload(h.getNginxDetails(), w, r) if err != nil { log.Warnf("Failed to send instance details payload: %v", err) } + case configRegex.MatchString(r.URL.Path): + if r.Method != http.MethodPut { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + err := h.updateConfig(w, r) + if err != nil { + log.Warnf("Failed to update config: %v", err) + } default: w.WriteHeader(http.StatusNotFound) _, err := fmt.Fprint(w, []byte("not found")) @@ -132,3 +177,84 @@ func (h *NginxHandler) getNginxDetails() []*proto.NginxDetails { return nginxDetails } + +func (h *NginxHandler) updateConfig(w http.ResponseWriter, r *http.Request) error { + log.Info("Updating config") + + r.ParseMultipartForm(32 << 20) + file, fileHeader, err := r.FormFile("file") + if err != nil { + return fmt.Errorf("can't read form file: %v", err) + } + defer file.Close() + + nginxDetails := h.getNginxDetails() + + log.Debug("Updating instances") + + for _, nginxDetail := range nginxDetails { + buf := bytes.NewBuffer(nil) + if _, err := io.Copy(buf, file); err != nil { + return fmt.Errorf("can't read file, %v", err) + } + + fullFilePath := nginxDetail.ConfPath + + protoFile := &proto.File{ + Name: fullFilePath, + Permissions: "0755", + Contents: buf.Bytes(), + } + + log.Tracef("protoFile: %v", protoFile) + + configApply, err := sdk.NewConfigApply(protoFile.GetName(), h.config.AllowedDirectoriesMap) + if err != nil { + return fmt.Errorf("unable to write config: %v", err) + } + + log.Debug("Writing config") + + err = h.env.WriteFiles(configApply, []*proto.File{protoFile}, "", h.config.AllowedDirectoriesMap) + if err != nil { + rollbackErr := configApply.Rollback(err) + return fmt.Errorf("config rollback failed: %v", rollbackErr) + } + + err = configApply.Complete() + if err != nil { + return fmt.Errorf("unable to write config: %v", err) + } + + log.Debug("File written") + + conf, err := h.nginxBinary.ReadConfig(fullFilePath, nginxDetail.NginxId, h.env.GetSystemUUID()) + if err != nil { + return fmt.Errorf("unable to read config: %v", err) + } + + log.Debug("ReadConfig") + + h.pipeline.Process(core.NewMessage(core.CommNginxConfig, conf)) + + log.Debug("Waiting for response or timeout") + select { + case response := <-h.responseChannel: + fmt.Fprintf(w, "%v", fileHeader.Header) + reqBodyBytes := new(bytes.Buffer) + if err := json.NewEncoder(reqBodyBytes).Encode(response); err != nil { + return fmt.Errorf("failed to encode response: %v", err) + + } + if _, err := w.Write(reqBodyBytes.Bytes()); err != nil { + return fmt.Errorf("failed to write response: %v", err) + } + return nil + case <-time.After(30 * time.Second): + log.Warn("Config update failed: timeout") + w.WriteHeader(http.StatusRequestTimeout) + return nil + } + } + return nil +} diff --git a/src/plugins/agent_api_test.go b/src/plugins/agent_api_test.go index 2b243167f..29a2d2a3c 100644 --- a/src/plugins/agent_api_test.go +++ b/src/plugins/agent_api_test.go @@ -1,13 +1,24 @@ package plugins import ( + "bytes" + "context" "encoding/json" + "io" + "io/fs" + "mime/multipart" "net/http" "net/http/httptest" + "os" + "path/filepath" "testing" "github.com/nginx/agent/sdk/v2/proto" + "github.com/nginx/agent/v2/src/core" + "github.com/nginx/agent/v2/src/core/config" + tutils "github.com/nginx/agent/v2/test/utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestNginxHandler_sendInstanceDetailsPayload(t *testing.T) { @@ -68,7 +79,7 @@ func TestNginxHandler_sendInstanceDetailsPayload(t *testing.T) { var nginxDetailsResponse []*proto.NginxDetails err = json.Unmarshal(respRec.Body.Bytes(), &nginxDetailsResponse) - assert.Nil(t, err) + assert.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) assert.True(t, json.Valid(respRec.Body.Bytes())) @@ -76,3 +87,55 @@ func TestNginxHandler_sendInstanceDetailsPayload(t *testing.T) { }) } } + +func TestNginxHandler_updateConfig(t *testing.T) { + tests := []struct { + name string + configUpdate string + }{ + { + name: "update config", + configUpdate: "# test", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Skip() + w := httptest.NewRecorder() + path := "/nginx/config/" + + file, err := os.CreateTemp(t.TempDir(), "file") + require.NoError(t, err) + defer file.Close() + + err = os.WriteFile(file.Name(), []byte(tt.configUpdate), fs.FileMode(os.O_RDWR)) + require.NoError(t, err) + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile("file", filepath.Base(file.Name())) + require.NoError(t, err) + io.Copy(part, file) + writer.Close() + + r := httptest.NewRequest(http.MethodPut, path, body) + r.Header.Set("Content-Type", writer.FormDataContentType()) + + h := &NginxHandler{ + config: config.Defaults, + env: &core.EnvironmentType{}, + pipeline: core.NewMessagePipe(context.TODO()), + nginxBinary: tutils.NewMockNginxBinary(), + responseChannel: make(chan *proto.Command_NginxConfigResponse), + } + + err = h.updateConfig(w, r) + assert.NoError(t, err) + + resp := w.Result() + defer resp.Body.Close() + + assert.Equal(t, "# test", w.Body.String()) + }) + } +} diff --git a/src/plugins/nginx.go b/src/plugins/nginx.go index afe81eb32..c6e40e2b0 100644 --- a/src/plugins/nginx.go +++ b/src/plugins/nginx.go @@ -104,7 +104,12 @@ func (n *Nginx) Process(message *core.Message) { switch cmd := message.Data().(type) { case *proto.Command: n.processCmd(cmd) + case *proto.NginxConfig: + log.Debug("writeConfigAndReloadNginx") + status := n.writeConfigAndReloadNginx("123", cmd) + n.messagePipeline.Process(core.NewMessage(core.RestAPIConfigApplyResponse, status)) } + case core.NginxConfigUpload: switch cfg := message.Data().(type) { case *proto.ConfigDescriptor: @@ -258,28 +263,49 @@ func (n *Nginx) processCmd(cmd *proto.Command) { func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) (status *proto.Command_NginxConfigResponse) { log.Debugf("Applying config for message id, %s", cmd.GetMeta().MessageId) - n.messagePipeline.Process(core.NewMessage(core.NginxConfigValidationPending, &proto.AgentActivityStatus{ - Status: &proto.AgentActivityStatus_NginxConfigStatus{ - NginxConfigStatus: &proto.NginxConfigStatus{ - CorrelationId: cmd.Meta.MessageId, - Status: proto.NginxConfigStatus_PENDING, - Message: "config apply pending", - }, - }, - })) + config, err := n.cmdr.Download(context.Background(), cmd.GetMeta()) + if err != nil { + status.NginxConfigResponse.Status = newErrStatus("Config apply failed (download): " + err.Error()).CmdStatus + return status + } + + status = n.writeConfigAndReloadNginx(cmd.Meta.MessageId, config) - status = &proto.Command_NginxConfigResponse{ + uploadResponse := &proto.Command_NginxConfigResponse{ NginxConfigResponse: &proto.NginxConfigResponse{ - Status: newOKStatus("config apply request successfully processed").CmdStatus, - Action: proto.NginxConfigAction_APPLY, - ConfigData: cfg.NginxConfig.ConfigData, + Action: proto.NginxConfigAction_UNKNOWN, + Status: newOKStatus("config uploaded status").CmdStatus, + ConfigData: nil, }, } - config, err := n.cmdr.Download(context.Background(), cmd.GetMeta()) + err = n.uploadConfig( + &proto.ConfigDescriptor{ + SystemId: n.env.GetSystemUUID(), + NginxId: config.GetConfigData().GetNginxId(), + }, + cmd.Meta.GetMessageId(), + ) if err != nil { - status.NginxConfigResponse.Status = newErrStatus("Config apply failed (download): " + err.Error()).CmdStatus - return status + uploadResponse.NginxConfigResponse.Status = newErrStatus("config uploaded error: " + err.Error()).CmdStatus + } + + uploadResponseCommand := newStatusCommand(cmd) + uploadResponseCommand.Data = uploadResponse + + n.messagePipeline.Process(core.NewMessage(core.CommResponse, uploadResponseCommand)) + + log.Debug("Config Apply Complete") + return status +} + +func (n *Nginx) writeConfigAndReloadNginx(messageId string, config *proto.NginxConfig) *proto.Command_NginxConfigResponse { + status := &proto.Command_NginxConfigResponse{ + NginxConfigResponse: &proto.NginxConfigResponse{ + Status: newOKStatus("config applied successfully").CmdStatus, + Action: proto.NginxConfigAction_APPLY, + ConfigData: config.ConfigData, + }, } if config.GetConfigData().GetNginxId() == "" { @@ -287,16 +313,18 @@ func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) return status } - log.Debugf("Disabling file watcher") + log.Debugf("config.GetConfigData().GetNginxId() %s", config.GetConfigData().GetNginxId()) + + log.Debug("Disabling file watcher") n.messagePipeline.Process(core.NewMessage(core.FileWatcherEnabled, false)) nginx := n.nginxBinary.GetNginxDetailsByID(config.GetConfigData().GetNginxId()) - if nginx == nil || nginx == (&proto.NginxDetails{}) { message := fmt.Sprintf("Config apply failed (preflight): no Nginx instance found for %v", config.GetConfigData().GetNginxId()) return n.handleErrorStatus(status, message) } + log.Debugf("WriteConfig start %v", config) configApply, err := n.nginxBinary.WriteConfig(config) if err != nil { if configApply != nil { @@ -309,7 +337,7 @@ func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) configRollbackResponse := ConfigRollbackResponse{ succeeded: succeeded, - correlationId: cmd.Meta.MessageId, + correlationId: messageId, timestamp: types.TimestampNow(), nginxDetails: nginx, } @@ -317,32 +345,60 @@ func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) } message := fmt.Sprintf("Config apply failed (write): " + err.Error()) + return n.handleErrorStatus(status, message) + } - n.messagePipeline.Process(core.NewMessage(core.NginxConfigApplyFailed, &proto.AgentActivityStatus{ - Status: &proto.AgentActivityStatus_NginxConfigStatus{ - NginxConfigStatus: &proto.NginxConfigStatus{ - CorrelationId: cmd.Meta.MessageId, - Status: proto.NginxConfigStatus_ERROR, - Message: message, - }, - }, - })) + log.Debug("Validating config") + + err = n.nginxBinary.ValidateConfig(nginx.NginxId, nginx.ProcessPath, nginx.ConfPath, config, configApply) + if err == nil { + _, err = n.nginxBinary.ReadConfig(nginx.GetConfPath(), config.GetConfigData().GetNginxId(), n.env.GetSystemUUID()) + log.Debug("Reading config") + } + if err != nil { + if configApply != nil { + succeeded := true + + if rollbackErr := configApply.Rollback(err); rollbackErr != nil { + log.Errorf("Config rollback failed: %v", rollbackErr) + succeeded = false + } + + configRollbackResponse := ConfigRollbackResponse{ + succeeded: succeeded, + correlationId: messageId, + timestamp: types.TimestampNow(), + nginxDetails: nginx, + } + n.messagePipeline.Process(core.NewMessage(core.ConfigRollbackResponse, configRollbackResponse)) + } + message := fmt.Sprintf("Config apply failed (write): " + err.Error()) return n.handleErrorStatus(status, message) + } else if configApply != nil { + if err = configApply.Complete(); err != nil { + log.Errorf("Config complete failed: %v", err) + } } - go n.validateConfig(nginx, cmd.Meta.MessageId, config, configApply) + log.Debug("Reloading") - // If the NGINX config can be validated with the validationTimeout the result will be returned straight away. - // This is timeout is temporary to ensure we support backwards compatibility. In a future release this timeout - // will be removed. - select { - case result := <-n.configApplyStatusChannel: - return result - case <-time.After(validationTimeout): - log.Debugf("Validation of the NGINX config in taking longer than the validationTimeout %s", validationTimeout) - return status + reloadErr := n.nginxBinary.Reload(nginx.ProcessId, nginx.ProcessPath) + if reloadErr != nil { + status.NginxConfigResponse.Status = newErrStatus("Config apply failed (write): " + reloadErr.Error()).CmdStatus } + nginxReloadEventMeta := NginxReloadResponse{ + succeeded: reloadErr == nil, + correlationId: messageId, + timestamp: types.TimestampNow(), + nginxDetails: nginx, + } + n.messagePipeline.Process(core.NewMessage(core.NginxReloadComplete, nginxReloadEventMeta)) + + log.Debug("Enabling file watcher") + n.messagePipeline.Process(core.NewMessage(core.FileWatcherEnabled, true)) + + return status } // This function will run a nginx config validation in a separate go routine. If the validation takes less than 15 seconds then the result is returned straight away, diff --git a/src/plugins/nginx_test.go b/src/plugins/nginx_test.go index 6ae8b3e37..f201edd93 100644 --- a/src/plugins/nginx_test.go +++ b/src/plugins/nginx_test.go @@ -4,7 +4,7 @@ import ( "context" "errors" "fmt" - "io/ioutil" + "os" "testing" "time" @@ -13,14 +13,12 @@ import ( "github.com/stretchr/testify/mock" "github.com/nginx/agent/sdk/v2" + agent_config "github.com/nginx/agent/sdk/v2/agent/config" "github.com/nginx/agent/sdk/v2/checksum" "github.com/nginx/agent/sdk/v2/grpc" "github.com/nginx/agent/sdk/v2/proto" - - agent_config "github.com/nginx/agent/sdk/v2/agent/config" "github.com/nginx/agent/v2/src/core" loadedConfig "github.com/nginx/agent/v2/src/core/config" - tutils "github.com/nginx/agent/v2/test/utils" ) @@ -216,10 +214,10 @@ func TestNginxConfigApply(t *testing.T) { test := test t.Run(fmt.Sprintf("%d", idx), func(tt *testing.T) { dir := t.TempDir() - tempConf, err := ioutil.TempFile(dir, "nginx.conf") + tempConf, err := os.CreateTemp(dir, "nginx.conf") assert.NoError(t, err) - err = ioutil.WriteFile(tempConf.Name(), fourth, 0644) + err = os.WriteFile(tempConf.Name(), fourth, 0644) assert.NoError(t, err) ctx := context.TODO() @@ -545,10 +543,11 @@ func TestNginx_completeConfigApply(t *testing.T) { pluginUnderTest := NewNginx(commandClient, binary, env, &loadedConfig.Config{Features: []string{agent_config.FeatureNginxConfig}}) dir := t.TempDir() - tempConf, err := ioutil.TempFile(dir, "nginx.conf") + tempConf, err := os.CreateTemp(dir, "nginx.conf") assert.NoError(t, err) allowedDirectoriesMap := map[string]struct{}{dir: {}} configApply, err := sdk.NewConfigApply(tempConf.Name(), allowedDirectoriesMap) + assert.NoError(t, err) response := &NginxConfigValidationResponse{ err: nil, @@ -631,10 +630,11 @@ func TestNginx_rollbackConfigApply(t *testing.T) { pluginUnderTest := NewNginx(commandClient, binary, env, &loadedConfig.Config{Features: []string{agent_config.FeatureNginxConfig}}) dir := t.TempDir() - tempConf, err := ioutil.TempFile(dir, "nginx.conf") + tempConf, err := os.CreateTemp(dir, "nginx.conf") assert.NoError(t, err) allowedDirectoriesMap := map[string]struct{}{dir: {}} configApply, err := sdk.NewConfigApply(tempConf.Name(), allowedDirectoriesMap) + assert.NoError(t, err) response := &NginxConfigValidationResponse{ err: errors.New("Failure"), diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/core/nginx.go b/test/performance/vendor/github.com/nginx/agent/v2/src/core/nginx.go index 164a89302..ff36d93bc 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/core/nginx.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/core/nginx.go @@ -341,7 +341,7 @@ func (n *NginxBinaryType) WriteConfig(config *proto.NginxConfig) (*sdk.ConfigApp } // Ensure all aux files are within the allowed list directories. - if err := ensureFilesAllowed(auxFiles, n.config.AllowedDirectoriesMap, config.Zaux.RootDirectory); err != nil { + if err := ensureFilesAllowed(auxFiles, n.config.AllowedDirectoriesMap, config.GetZaux().GetRootDirectory()); err != nil { return nil, err } diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/core/topics.go b/test/performance/vendor/github.com/nginx/agent/v2/src/core/topics.go index 41dc95b57..022550740 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/core/topics.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/core/topics.go @@ -45,4 +45,5 @@ const ( ConfigRollbackResponse = "config.rollback.response" DataplaneSoftwareDetailsUpdated = "dataplane.software.details.updated" EnableExtension = "enable.extension" + RestAPIConfigApplyResponse = "rest.api.config.apply.response" ) diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go index 5bb369be2..8b444492e 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go @@ -5,9 +5,12 @@ import ( "context" "encoding/json" "fmt" + "io" "net/http" "regexp" + "time" + "github.com/nginx/agent/sdk/v2" "github.com/nginx/agent/sdk/v2/proto" "github.com/nginx/agent/v2/src/core" "github.com/nginx/agent/v2/src/core/config" @@ -18,22 +21,31 @@ import ( type AgentAPI struct { config *config.Config env core.Environment + pipeline core.MessagePipeInterface server http.Server nginxBinary core.NginxBinary nginxHandler *NginxHandler } type NginxHandler struct { - env core.Environment - nginxBinary core.NginxBinary + config *config.Config + env core.Environment + pipeline core.MessagePipeInterface + nginxBinary core.NginxBinary + responseChannel chan *proto.Command_NginxConfigResponse } func NewAgentAPI(config *config.Config, env core.Environment, nginxBinary core.NginxBinary) *AgentAPI { - return &AgentAPI{config: config, env: env, nginxBinary: nginxBinary} + return &AgentAPI{ + config: config, + env: env, + nginxBinary: nginxBinary, + } } -func (a *AgentAPI) Init(core.MessagePipeInterface) { +func (a *AgentAPI) Init(pipeline core.MessagePipeInterface) { log.Info("Agent API initializing") + a.pipeline = pipeline go a.createHttpServer() } @@ -46,6 +58,16 @@ func (a *AgentAPI) Close() { func (a *AgentAPI) Process(message *core.Message) { log.Tracef("Process function in the agent_api.go, %s %v", message.Topic(), message.Data()) + + switch message.Topic() { + case core.RestAPIConfigApplyResponse: + switch response := message.Data().(type) { + case *proto.Command_NginxConfigResponse: + a.nginxHandler.responseChannel <- response + default: + log.Warnf("Unknown Command_NginxConfigResponse type: %T(%v)", message.Data(), message.Data()) + } + } } func (a *AgentAPI) Info() *core.Info { @@ -53,21 +75,28 @@ func (a *AgentAPI) Info() *core.Info { } func (a *AgentAPI) Subscriptions() []string { - return []string{} + return []string{core.RestAPIConfigApplyResponse} } func (a *AgentAPI) createHttpServer() { + a.nginxHandler = &NginxHandler{ + config: a.config, + pipeline: a.pipeline, + env: a.env, + nginxBinary: a.nginxBinary, + responseChannel: make(chan *proto.Command_NginxConfigResponse), + } + mux := http.NewServeMux() - a.nginxHandler = &NginxHandler{a.env, a.nginxBinary} mux.Handle("/nginx/", a.nginxHandler) - log.Debug("Starting Agent API HTTP server") - a.server = http.Server{ Addr: fmt.Sprintf(":%d", a.config.AgentAPI.Port), Handler: mux, } + log.Debug("Starting Agent API HTTP server") + if err := a.server.ListenAndServe(); err != http.ErrServerClosed { log.Fatalf("error listening to port: %v", err) } @@ -75,16 +104,32 @@ func (a *AgentAPI) createHttpServer() { var ( instancesRegex = regexp.MustCompile(`^\/nginx[\/]*$`) + configRegex = regexp.MustCompile(`^\/nginx/config[\/]*$`) ) func (h *NginxHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { w.Header().Set("content-type", "application/json") switch { - case r.Method == http.MethodGet && instancesRegex.MatchString(r.URL.Path): + case instancesRegex.MatchString(r.URL.Path): + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + err := sendInstanceDetailsPayload(h.getNginxDetails(), w, r) if err != nil { log.Warnf("Failed to send instance details payload: %v", err) } + case configRegex.MatchString(r.URL.Path): + if r.Method != http.MethodPut { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + err := h.updateConfig(w, r) + if err != nil { + log.Warnf("Failed to update config: %v", err) + } default: w.WriteHeader(http.StatusNotFound) _, err := fmt.Fprint(w, []byte("not found")) @@ -132,3 +177,84 @@ func (h *NginxHandler) getNginxDetails() []*proto.NginxDetails { return nginxDetails } + +func (h *NginxHandler) updateConfig(w http.ResponseWriter, r *http.Request) error { + log.Info("Updating config") + + r.ParseMultipartForm(32 << 20) + file, fileHeader, err := r.FormFile("file") + if err != nil { + return fmt.Errorf("can't read form file: %v", err) + } + defer file.Close() + + nginxDetails := h.getNginxDetails() + + log.Debug("Updating instances") + + for _, nginxDetail := range nginxDetails { + buf := bytes.NewBuffer(nil) + if _, err := io.Copy(buf, file); err != nil { + return fmt.Errorf("can't read file, %v", err) + } + + fullFilePath := nginxDetail.ConfPath + + protoFile := &proto.File{ + Name: fullFilePath, + Permissions: "0755", + Contents: buf.Bytes(), + } + + log.Tracef("protoFile: %v", protoFile) + + configApply, err := sdk.NewConfigApply(protoFile.GetName(), h.config.AllowedDirectoriesMap) + if err != nil { + return fmt.Errorf("unable to write config: %v", err) + } + + log.Debug("Writing config") + + err = h.env.WriteFiles(configApply, []*proto.File{protoFile}, "", h.config.AllowedDirectoriesMap) + if err != nil { + rollbackErr := configApply.Rollback(err) + return fmt.Errorf("config rollback failed: %v", rollbackErr) + } + + err = configApply.Complete() + if err != nil { + return fmt.Errorf("unable to write config: %v", err) + } + + log.Debug("File written") + + conf, err := h.nginxBinary.ReadConfig(fullFilePath, nginxDetail.NginxId, h.env.GetSystemUUID()) + if err != nil { + return fmt.Errorf("unable to read config: %v", err) + } + + log.Debug("ReadConfig") + + h.pipeline.Process(core.NewMessage(core.CommNginxConfig, conf)) + + log.Debug("Waiting for response or timeout") + select { + case response := <-h.responseChannel: + fmt.Fprintf(w, "%v", fileHeader.Header) + reqBodyBytes := new(bytes.Buffer) + if err := json.NewEncoder(reqBodyBytes).Encode(response); err != nil { + return fmt.Errorf("failed to encode response: %v", err) + + } + if _, err := w.Write(reqBodyBytes.Bytes()); err != nil { + return fmt.Errorf("failed to write response: %v", err) + } + return nil + case <-time.After(30 * time.Second): + log.Warn("Config update failed: timeout") + w.WriteHeader(http.StatusRequestTimeout) + return nil + } + } + return nil +} diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go index afe81eb32..c6e40e2b0 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go @@ -104,7 +104,12 @@ func (n *Nginx) Process(message *core.Message) { switch cmd := message.Data().(type) { case *proto.Command: n.processCmd(cmd) + case *proto.NginxConfig: + log.Debug("writeConfigAndReloadNginx") + status := n.writeConfigAndReloadNginx("123", cmd) + n.messagePipeline.Process(core.NewMessage(core.RestAPIConfigApplyResponse, status)) } + case core.NginxConfigUpload: switch cfg := message.Data().(type) { case *proto.ConfigDescriptor: @@ -258,28 +263,49 @@ func (n *Nginx) processCmd(cmd *proto.Command) { func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) (status *proto.Command_NginxConfigResponse) { log.Debugf("Applying config for message id, %s", cmd.GetMeta().MessageId) - n.messagePipeline.Process(core.NewMessage(core.NginxConfigValidationPending, &proto.AgentActivityStatus{ - Status: &proto.AgentActivityStatus_NginxConfigStatus{ - NginxConfigStatus: &proto.NginxConfigStatus{ - CorrelationId: cmd.Meta.MessageId, - Status: proto.NginxConfigStatus_PENDING, - Message: "config apply pending", - }, - }, - })) + config, err := n.cmdr.Download(context.Background(), cmd.GetMeta()) + if err != nil { + status.NginxConfigResponse.Status = newErrStatus("Config apply failed (download): " + err.Error()).CmdStatus + return status + } + + status = n.writeConfigAndReloadNginx(cmd.Meta.MessageId, config) - status = &proto.Command_NginxConfigResponse{ + uploadResponse := &proto.Command_NginxConfigResponse{ NginxConfigResponse: &proto.NginxConfigResponse{ - Status: newOKStatus("config apply request successfully processed").CmdStatus, - Action: proto.NginxConfigAction_APPLY, - ConfigData: cfg.NginxConfig.ConfigData, + Action: proto.NginxConfigAction_UNKNOWN, + Status: newOKStatus("config uploaded status").CmdStatus, + ConfigData: nil, }, } - config, err := n.cmdr.Download(context.Background(), cmd.GetMeta()) + err = n.uploadConfig( + &proto.ConfigDescriptor{ + SystemId: n.env.GetSystemUUID(), + NginxId: config.GetConfigData().GetNginxId(), + }, + cmd.Meta.GetMessageId(), + ) if err != nil { - status.NginxConfigResponse.Status = newErrStatus("Config apply failed (download): " + err.Error()).CmdStatus - return status + uploadResponse.NginxConfigResponse.Status = newErrStatus("config uploaded error: " + err.Error()).CmdStatus + } + + uploadResponseCommand := newStatusCommand(cmd) + uploadResponseCommand.Data = uploadResponse + + n.messagePipeline.Process(core.NewMessage(core.CommResponse, uploadResponseCommand)) + + log.Debug("Config Apply Complete") + return status +} + +func (n *Nginx) writeConfigAndReloadNginx(messageId string, config *proto.NginxConfig) *proto.Command_NginxConfigResponse { + status := &proto.Command_NginxConfigResponse{ + NginxConfigResponse: &proto.NginxConfigResponse{ + Status: newOKStatus("config applied successfully").CmdStatus, + Action: proto.NginxConfigAction_APPLY, + ConfigData: config.ConfigData, + }, } if config.GetConfigData().GetNginxId() == "" { @@ -287,16 +313,18 @@ func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) return status } - log.Debugf("Disabling file watcher") + log.Debugf("config.GetConfigData().GetNginxId() %s", config.GetConfigData().GetNginxId()) + + log.Debug("Disabling file watcher") n.messagePipeline.Process(core.NewMessage(core.FileWatcherEnabled, false)) nginx := n.nginxBinary.GetNginxDetailsByID(config.GetConfigData().GetNginxId()) - if nginx == nil || nginx == (&proto.NginxDetails{}) { message := fmt.Sprintf("Config apply failed (preflight): no Nginx instance found for %v", config.GetConfigData().GetNginxId()) return n.handleErrorStatus(status, message) } + log.Debugf("WriteConfig start %v", config) configApply, err := n.nginxBinary.WriteConfig(config) if err != nil { if configApply != nil { @@ -309,7 +337,7 @@ func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) configRollbackResponse := ConfigRollbackResponse{ succeeded: succeeded, - correlationId: cmd.Meta.MessageId, + correlationId: messageId, timestamp: types.TimestampNow(), nginxDetails: nginx, } @@ -317,32 +345,60 @@ func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) } message := fmt.Sprintf("Config apply failed (write): " + err.Error()) + return n.handleErrorStatus(status, message) + } - n.messagePipeline.Process(core.NewMessage(core.NginxConfigApplyFailed, &proto.AgentActivityStatus{ - Status: &proto.AgentActivityStatus_NginxConfigStatus{ - NginxConfigStatus: &proto.NginxConfigStatus{ - CorrelationId: cmd.Meta.MessageId, - Status: proto.NginxConfigStatus_ERROR, - Message: message, - }, - }, - })) + log.Debug("Validating config") + + err = n.nginxBinary.ValidateConfig(nginx.NginxId, nginx.ProcessPath, nginx.ConfPath, config, configApply) + if err == nil { + _, err = n.nginxBinary.ReadConfig(nginx.GetConfPath(), config.GetConfigData().GetNginxId(), n.env.GetSystemUUID()) + log.Debug("Reading config") + } + if err != nil { + if configApply != nil { + succeeded := true + + if rollbackErr := configApply.Rollback(err); rollbackErr != nil { + log.Errorf("Config rollback failed: %v", rollbackErr) + succeeded = false + } + + configRollbackResponse := ConfigRollbackResponse{ + succeeded: succeeded, + correlationId: messageId, + timestamp: types.TimestampNow(), + nginxDetails: nginx, + } + n.messagePipeline.Process(core.NewMessage(core.ConfigRollbackResponse, configRollbackResponse)) + } + message := fmt.Sprintf("Config apply failed (write): " + err.Error()) return n.handleErrorStatus(status, message) + } else if configApply != nil { + if err = configApply.Complete(); err != nil { + log.Errorf("Config complete failed: %v", err) + } } - go n.validateConfig(nginx, cmd.Meta.MessageId, config, configApply) + log.Debug("Reloading") - // If the NGINX config can be validated with the validationTimeout the result will be returned straight away. - // This is timeout is temporary to ensure we support backwards compatibility. In a future release this timeout - // will be removed. - select { - case result := <-n.configApplyStatusChannel: - return result - case <-time.After(validationTimeout): - log.Debugf("Validation of the NGINX config in taking longer than the validationTimeout %s", validationTimeout) - return status + reloadErr := n.nginxBinary.Reload(nginx.ProcessId, nginx.ProcessPath) + if reloadErr != nil { + status.NginxConfigResponse.Status = newErrStatus("Config apply failed (write): " + reloadErr.Error()).CmdStatus } + nginxReloadEventMeta := NginxReloadResponse{ + succeeded: reloadErr == nil, + correlationId: messageId, + timestamp: types.TimestampNow(), + nginxDetails: nginx, + } + n.messagePipeline.Process(core.NewMessage(core.NginxReloadComplete, nginxReloadEventMeta)) + + log.Debug("Enabling file watcher") + n.messagePipeline.Process(core.NewMessage(core.FileWatcherEnabled, true)) + + return status } // This function will run a nginx config validation in a separate go routine. If the validation takes less than 15 seconds then the result is returned straight away, From 8d53b69d30b100d082f5efb445c06990af792282 Mon Sep 17 00:00:00 2001 From: Dean Coakley Date: Tue, 22 Nov 2022 18:37:17 +0000 Subject: [PATCH 2/8] Remove rest config from README example --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index de25a16d4..36977d060 100644 --- a/README.md +++ b/README.md @@ -72,8 +72,6 @@ server: # host of the control plane host: 127.0.0.1 grpcPort: 54789 # control plane grpc port -api: - port: 9090 # nginx-agent http api # tls options - NOT RECOMMENDED FOR PRODUCTION tls: enable: false From c0a25cdd175085751a3f53cd923d7ecd415d22d8 Mon Sep 17 00:00:00 2001 From: dhurley Date: Mon, 5 Dec 2022 14:38:34 +0000 Subject: [PATCH 3/8] Add nginx config apply and status endpoints to the agent API --- main.go | 8 +- src/core/config/defaults.go | 4 +- src/core/config/types.go | 17 + src/core/nginx.go | 8 +- src/core/topics.go | 2 +- .../pkg/publisher/publisher_test.go | 8 +- src/plugins/agent_api.go | 332 +++++++++++++----- src/plugins/agent_api_test.go | 296 +++++++++++++++- src/plugins/nginx.go | 229 +++++------- src/plugins/nginx_test.go | 21 +- .../agent/v2/src/core/config/defaults.go | 4 +- .../nginx/agent/v2/src/core/config/types.go | 17 + .../nginx/agent/v2/src/core/nginx.go | 8 +- .../nginx/agent/v2/src/core/topics.go | 2 +- .../nginx/agent/v2/src/plugins/agent_api.go | 332 +++++++++++++----- .../nginx/agent/v2/src/plugins/nginx.go | 229 +++++------- 16 files changed, 1034 insertions(+), 483 deletions(-) diff --git a/main.go b/main.go index a02e2ee36..e90b0b7aa 100644 --- a/main.go +++ b/main.go @@ -141,12 +141,8 @@ func handleSignals( }() } -func connectionUnavilable(loadedConfig *config.Config) bool { - return loadedConfig.Server.Host == "" || loadedConfig.Server.GrpcPort == 0 -} - func createGrpcClients(ctx context.Context, loadedConfig *config.Config) (client.Controller, client.Commander, client.MetricReporter) { - if connectionUnavilable(loadedConfig) { + if !loadedConfig.IsGrpcServerConfigured() { log.Infof("GRPC clients not created") return nil, nil, nil } @@ -234,7 +230,7 @@ func loadPlugins(commander client.Commander, binary *core.NginxBinaryType, env * corePlugins = append(corePlugins, plugins.NewAdvancedMetrics(env, loadedConfig)) } - if loadedConfig.NginxAppProtect != (config.NginxAppProtect{}) { + if loadedConfig.IsNginxAppProtectConfigured() { napPlugin, err := plugins.NewNginxAppProtect(loadedConfig, env) if err == nil { corePlugins = append(corePlugins, napPlugin) diff --git a/src/core/config/defaults.go b/src/core/config/defaults.go index b5f0c9063..722ddcce4 100644 --- a/src/core/config/defaults.go +++ b/src/core/config/defaults.go @@ -234,8 +234,8 @@ var ( }, // API Config &IntFlag{ - Name: AgentAPIPort, - Usage: "The desired port to use for nginx-agent to expose for HTTP traffic.", + Name: AgentAPIPort, + Usage: "The desired port to use for nginx-agent to expose for HTTP traffic.", }, &StringFlag{ Name: AgentAPICert, diff --git a/src/core/config/types.go b/src/core/config/types.go index c65dec245..4ced9dcb3 100644 --- a/src/core/config/types.go +++ b/src/core/config/types.go @@ -38,6 +38,23 @@ type Config struct { NAPMonitoring NAPMonitoring `mapstructure:"nap_monitoring" yaml:"nap_monitoring,omitempty"` } +func (c *Config) IsGrpcServerConfigured() bool { + return c.Server.Host != "" && c.Server.GrpcPort != 0 +} + +func (c *Config) IsNginxAppProtectConfigured() bool { + return c.NginxAppProtect != (NginxAppProtect{}) +} + +func (c *Config) IsFeatureEnabled(feature string) bool { + for _, configFeature := range c.Features { + if configFeature == feature { + return true + } + } + return false +} + type Server struct { Host string `mapstructure:"host" yaml:"-"` GrpcPort int `mapstructure:"grpcPort" yaml:"-"` diff --git a/src/core/nginx.go b/src/core/nginx.go index 93cd0eca4..4b8f1e747 100644 --- a/src/core/nginx.go +++ b/src/core/nginx.go @@ -258,9 +258,11 @@ func (n *NginxBinaryType) ValidateConfig(processId, bin, configLocation string, log.Debugf("Validating config, %s for nginx process, %s", configLocation, processId) response, err := runCmd(bin, "-t", "-c", configLocation) if err != nil { - confFiles, auxFiles, err := sdk.GetNginxConfigFiles(config) - n.writeBackup(config, confFiles, auxFiles) - return fmt.Errorf("error running nginx -t -c %v:\n%s%v", configLocation, response, err) + confFiles, auxFiles, getNginxConfigFilesErr := sdk.GetNginxConfigFiles(config) + if getNginxConfigFilesErr == nil { + n.writeBackup(config, confFiles, auxFiles) + } + return fmt.Errorf("error running nginx -t -c %v:\n%s", configLocation, response) } log.Infof("Config validated:\n%s", response) diff --git a/src/core/topics.go b/src/core/topics.go index d4e64b780..67a6e1ff0 100644 --- a/src/core/topics.go +++ b/src/core/topics.go @@ -52,5 +52,5 @@ const ( ConfigRollbackResponse = "config.rollback.response" DataplaneSoftwareDetailsUpdated = "dataplane.software.details.updated" EnableExtension = "enable.extension" - RestAPIConfigApplyResponse = "rest.api.config.apply.response" + AgentAPIConfigApplyResponse = "agent.api.config.apply.response" ) diff --git a/src/extensions/advanced-metrics/pkg/publisher/publisher_test.go b/src/extensions/advanced-metrics/pkg/publisher/publisher_test.go index 4406d8f13..d0c4522ca 100644 --- a/src/extensions/advanced-metrics/pkg/publisher/publisher_test.go +++ b/src/extensions/advanced-metrics/pkg/publisher/publisher_test.go @@ -28,11 +28,11 @@ func TestPublisher(t *testing.T) { dimensionsLookups map[int]map[int]string }{ { - name: "no metric with no dimension", - schema: schema.NewSchema([]*schema.Field{}...), - samples: map[string]*sample.Sample{}, + name: "no metric with no dimension", + schema: schema.NewSchema([]*schema.Field{}...), + samples: map[string]*sample.Sample{}, dimensionsLookups: map[int]map[int]string{}, - expectedMetrics: []*MetricSet{}, + expectedMetrics: []*MetricSet{}, }, { name: "single metric with single dimension", diff --git a/src/plugins/agent_api.go b/src/plugins/agent_api.go index 2d5229251..33697fcbc 100644 --- a/src/plugins/agent_api.go +++ b/src/plugins/agent_api.go @@ -14,9 +14,11 @@ import ( "fmt" "io" "net/http" + "os" "regexp" "time" + "github.com/google/uuid" "github.com/nginx/agent/sdk/v2" "github.com/nginx/agent/sdk/v2/proto" "github.com/nginx/agent/v2/src/core" @@ -27,6 +29,19 @@ import ( log "github.com/sirupsen/logrus" ) +const ( + okStatus = "OK" + pendingStatus = "PENDING" + errorStatus = "ERROR" + unknownStatus = "UNKNOWN" +) + +var ( + instancesRegex = regexp.MustCompile(`^\/nginx[\/]*$`) + configRegex = regexp.MustCompile(`^\/nginx/config[\/]*$`) + configStatusRegex = regexp.MustCompile(`^\/nginx/config/status[\/]*$`) +) + type AgentAPI struct { config *config.Config env core.Environment @@ -38,11 +53,39 @@ type AgentAPI struct { } type NginxHandler struct { - config *config.Config - env core.Environment - pipeline core.MessagePipeInterface - nginxBinary core.NginxBinary - responseChannel chan *proto.Command_NginxConfigResponse + config *config.Config + env core.Environment + pipeline core.MessagePipeInterface + nginxBinary core.NginxBinary + responseChannel chan *proto.Command_NginxConfigResponse + configResponseStatus *proto.NginxConfigStatus +} + +type AgentAPIConfigApplyRequest struct { + correlationId string + config *proto.NginxConfig +} + +type NginxInstanceResponse struct { + NginxId string `json:"nginx_id"` + Message string `json:"message"` + Status string `json:"status"` +} + +type AgentAPIConfigApplyResponse struct { + CorrelationId string `json:"correlation_id"` + NginxInstances []NginxInstanceResponse `json:"nginx_instances"` +} + +type AgentAPICommonResponse struct { + CorrelationId string `json:"correlation_id"` + Message string `json:"message"` +} + +type AgentAPIConfigApplyStatusResponse struct { + CorrelationId string `json:"correlation_id"` + Message string `json:"message"` + Status string `json:"status"` } const ( @@ -50,11 +93,6 @@ const ( jsonMimeType = "application/json" ) -var ( - instancesRegex = regexp.MustCompile(`^\/nginx[\/]*$`) - configRegex = regexp.MustCompile(`^\/nginx/config[\/]*$`) -) - func NewAgentAPI(config *config.Config, env core.Environment, nginxBinary core.NginxBinary) *AgentAPI { return &AgentAPI{ config: config, @@ -81,7 +119,7 @@ func (a *AgentAPI) Process(message *core.Message) { log.Tracef("Process function in the agent_api.go, %s %v", message.Topic(), message.Data()) switch message.Topic() { - case core.RestAPIConfigApplyResponse: + case core.AgentAPIConfigApplyResponse: switch response := message.Data().(type) { case *proto.Command_NginxConfigResponse: a.nginxHandler.responseChannel <- response @@ -95,6 +133,13 @@ func (a *AgentAPI) Process(message *core.Message) { default: log.Warnf("Unknown MetricReport type: %T(%v)", message.Data(), message.Data()) } + case core.NginxConfigValidationPending, core.NginxConfigApplyFailed, core.NginxConfigApplySucceeded: + switch response := message.Data().(type) { + case *proto.AgentActivityStatus: + a.nginxHandler.configResponseStatus = response.GetNginxConfigStatus() + default: + log.Errorf("Expected the type %T but got %T", &proto.AgentActivityStatus{}, response) + } } } func (a *AgentAPI) Info() *core.Info { @@ -102,16 +147,23 @@ func (a *AgentAPI) Info() *core.Info { } func (a *AgentAPI) Subscriptions() []string { - return []string{core.RestAPIConfigApplyResponse, core.MetricReport} + return []string{ + core.AgentAPIConfigApplyResponse, + core.MetricReport, + core.NginxConfigValidationPending, + core.NginxConfigApplyFailed, + core.NginxConfigApplySucceeded, + } } func (a *AgentAPI) createHttpServer() { a.nginxHandler = &NginxHandler{ - config: a.config, - pipeline: a.pipeline, - env: a.env, - nginxBinary: a.nginxBinary, - responseChannel: make(chan *proto.Command_NginxConfigResponse), + config: a.config, + pipeline: a.pipeline, + env: a.env, + nginxBinary: a.nginxBinary, + responseChannel: make(chan *proto.Command_NginxConfigResponse), + configResponseStatus: &proto.NginxConfigStatus{}, } mux := http.NewServeMux() @@ -121,7 +173,7 @@ func (a *AgentAPI) createHttpServer() { registerer.MustRegister(a.exporter) mux.Handle("/metrics", promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{})) mux.Handle("/nginx/", a.nginxHandler) - + a.server = http.Server{ Addr: fmt.Sprintf(":%d", a.config.AgentAPI.Port), Handler: mux, @@ -151,7 +203,7 @@ func (h *NginxHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - err := sendInstanceDetailsPayload(h.getNginxDetails(), w, r) + err := h.sendInstanceDetailsPayload(w, r) if err != nil { log.Warnf("Failed to send instance details payload: %v", err) } @@ -165,6 +217,16 @@ func (h *NginxHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err != nil { log.Warnf("Failed to update config: %v", err) } + case configStatusRegex.MatchString(r.URL.Path): + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + err := h.getConfigStatus(w, r) + if err != nil { + log.Warnf("Failed to get config status: %v", err) + } default: w.WriteHeader(http.StatusNotFound) _, err := fmt.Fprint(w, []byte("not found")) @@ -174,7 +236,8 @@ func (h *NginxHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } -func sendInstanceDetailsPayload(nginxDetails []*proto.NginxDetails, w http.ResponseWriter, r *http.Request) error { +func (h *NginxHandler) sendInstanceDetailsPayload(w http.ResponseWriter, r *http.Request) error { + nginxDetails := h.getNginxDetails() w.WriteHeader(http.StatusOK) if len(nginxDetails) == 0 { @@ -187,20 +250,108 @@ func sendInstanceDetailsPayload(nginxDetails []*proto.NginxDetails, w http.Respo return nil } - respBody := new(bytes.Buffer) - err := json.NewEncoder(respBody).Encode(nginxDetails) + return writeObjectToResponseBody(w, nginxDetails) +} + +func (h *NginxHandler) updateConfig(w http.ResponseWriter, r *http.Request) error { + correlationId := uuid.New().String() + + buf, err := readFileFromRequest(r) if err != nil { - return fmt.Errorf("failed to encode payload: %v", err) + w.WriteHeader(http.StatusBadRequest) + response := AgentAPICommonResponse{ + CorrelationId: correlationId, + Message: err.Error(), + } + return writeObjectToResponseBody(w, response) } - _, err = fmt.Fprint(w, respBody) - if err != nil { - return fmt.Errorf("failed to send payload: %v", err) + nginxDetails := h.getNginxDetails() + + for _, nginxDetail := range nginxDetails { + err := h.applyNginxConfig(nginxDetail, buf, correlationId) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + response := AgentAPICommonResponse{ + CorrelationId: correlationId, + Message: err.Error(), + } + return writeObjectToResponseBody(w, response) + } + } + + if len(nginxDetails) > 0 { + agentAPIConfigApplyResponse := &AgentAPIConfigApplyResponse{CorrelationId: correlationId, NginxInstances: make([]NginxInstanceResponse, 0)} + + select { + case response := <-h.responseChannel: + nginxResponse := NginxInstanceResponse{ + NginxId: response.NginxConfigResponse.GetConfigData().GetNginxId(), + Message: response.NginxConfigResponse.GetStatus().GetMessage(), + Status: okStatus, + } + + if response.NginxConfigResponse.GetStatus().GetStatus() != proto.CommandStatusResponse_CMD_OK { + w.WriteHeader(http.StatusBadRequest) + nginxResponse.Status = errorStatus + } else { + if response.NginxConfigResponse.GetStatus().GetMessage() == configAppliedProcessedResponse { + w.WriteHeader(http.StatusRequestTimeout) + nginxResponse.Status = pendingStatus + } else { + w.WriteHeader(http.StatusOK) + } + } + + agentAPIConfigApplyResponse.NginxInstances = append(agentAPIConfigApplyResponse.NginxInstances, nginxResponse) + + // If the number of responses match the number of NGINX instances then return a response. + // Otherwise wait until all config apply requests are complete for all NGINX instances. + if len(agentAPIConfigApplyResponse.NginxInstances) == len(nginxDetails) { + return writeObjectToResponseBody(w, agentAPIConfigApplyResponse) + } + + case <-time.After(validationTimeout): + w.WriteHeader(http.StatusRequestTimeout) + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ + CorrelationId: correlationId, + Message: "Pending config apply", + Status: pendingStatus, + } + + return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) + } + } else { + w.WriteHeader(http.StatusInternalServerError) + response := AgentAPICommonResponse{ + CorrelationId: correlationId, + Message: "No NGINX instances found", + } + return writeObjectToResponseBody(w, response) } + w.WriteHeader(http.StatusInternalServerError) return nil } +func readFileFromRequest(r *http.Request) (*bytes.Buffer, error) { + err := r.ParseMultipartForm(32 << 20) + if err != nil { + log.Errorf("unable to parse config apply request, %v", err) + } + file, _, err := r.FormFile("file") + if err != nil { + return nil, fmt.Errorf("can't read form file: %v", err) + } + defer file.Close() + + buf := bytes.NewBuffer(nil) + if _, err := io.Copy(buf, file); err != nil { + return nil, fmt.Errorf("can't read file, %v", err) + } + return buf, nil +} + func (h *NginxHandler) getNginxDetails() []*proto.NginxDetails { var nginxDetails []*proto.NginxDetails @@ -212,86 +363,99 @@ func (h *NginxHandler) getNginxDetails() []*proto.NginxDetails { return nginxDetails } -func (h *NginxHandler) updateConfig(w http.ResponseWriter, r *http.Request) error { - log.Info("Updating config") +func (h *NginxHandler) applyNginxConfig(nginxDetail *proto.NginxDetails, buf *bytes.Buffer, correlationId string) error { + fullFilePath := nginxDetail.ConfPath - err := r.ParseMultipartForm(32 << 20) + // Create backup of nginx.conf file on host + data, err := os.ReadFile(fullFilePath) if err != nil { - log.Errorf("unable to parse config apply request, %v", err) + return fmt.Errorf("unable to read file %s: %v", fullFilePath, err) + } + + protoFile := &proto.File{ + Name: fullFilePath, + Permissions: "0755", + Contents: buf.Bytes(), } - file, fileHeader, err := r.FormFile("file") + + configApply, err := sdk.NewConfigApply(protoFile.GetName(), h.config.AllowedDirectoriesMap) if err != nil { - return fmt.Errorf("can't read form file: %v", err) + return fmt.Errorf("unable to write config: %v", err) } - defer file.Close() - nginxDetails := h.getNginxDetails() + // Temporarily write the new nginx.conf to disk + err = h.env.WriteFiles(configApply, []*proto.File{protoFile}, "", h.config.AllowedDirectoriesMap) + if err != nil { + rollbackErr := configApply.Rollback(err) + return fmt.Errorf("config rollback failed: %v", rollbackErr) + } - log.Debug("Updating instances") + // Create NginxConfig object for new nginx.conf + conf, err := h.nginxBinary.ReadConfig(fullFilePath, nginxDetail.NginxId, h.env.GetSystemUUID()) + if err != nil { + rollbackErr := configApply.Rollback(err) + return fmt.Errorf("unable to read config: %v", rollbackErr) + } - for _, nginxDetail := range nginxDetails { - buf := bytes.NewBuffer(nil) - if _, err := io.Copy(buf, file); err != nil { - return fmt.Errorf("can't read file, %v", err) - } + // Write back the original nginx.conf + err = os.WriteFile(fullFilePath, data, 0644) + if err != nil { + rollbackErr := configApply.Rollback(err) + return fmt.Errorf("unable to write file %s: %v", fullFilePath, rollbackErr) + } - fullFilePath := nginxDetail.ConfPath + // Send a config apply request to the nginx.go plugin + h.pipeline.Process(core.NewMessage(core.CommNginxConfig, &AgentAPIConfigApplyRequest{correlationId: correlationId, config: conf})) + return nil +} - protoFile := &proto.File{ - Name: fullFilePath, - Permissions: "0755", - Contents: buf.Bytes(), - } +func (h *NginxHandler) getConfigStatus(w http.ResponseWriter, r *http.Request) error { + correlationId := r.URL.Query().Get("correlation_id") - log.Tracef("protoFile: %v", protoFile) + if correlationId == "" { + w.WriteHeader(http.StatusBadRequest) - configApply, err := sdk.NewConfigApply(protoFile.GetName(), h.config.AllowedDirectoriesMap) - if err != nil { - return fmt.Errorf("unable to write config: %v", err) + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ + CorrelationId: correlationId, + Message: "Missing required query parameter correlation_id", + Status: unknownStatus, } - log.Debug("Writing config") - - err = h.env.WriteFiles(configApply, []*proto.File{protoFile}, "", h.config.AllowedDirectoriesMap) - if err != nil { - rollbackErr := configApply.Rollback(err) - return fmt.Errorf("config rollback failed: %v", rollbackErr) - } + return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) + } - err = configApply.Complete() - if err != nil { - return fmt.Errorf("unable to write config: %v", err) + if h.configResponseStatus.GetCorrelationId() != correlationId { + w.WriteHeader(http.StatusNotFound) + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ + CorrelationId: correlationId, + Message: fmt.Sprintf("Unable to find a config apply request with the correlation_id %s", correlationId), + Status: unknownStatus, } - log.Debug("File written") + return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) + } - conf, err := h.nginxBinary.ReadConfig(fullFilePath, nginxDetail.NginxId, h.env.GetSystemUUID()) - if err != nil { - return fmt.Errorf("unable to read config: %v", err) - } + w.WriteHeader(http.StatusOK) - log.Debug("ReadConfig") + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ + CorrelationId: correlationId, + Message: h.configResponseStatus.Message, + Status: h.configResponseStatus.Status.String(), + } - h.pipeline.Process(core.NewMessage(core.CommNginxConfig, conf)) + return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) +} - log.Debug("Waiting for response or timeout") - select { - case response := <-h.responseChannel: - fmt.Fprintf(w, "%v", fileHeader.Header) - reqBodyBytes := new(bytes.Buffer) - if err := json.NewEncoder(reqBodyBytes).Encode(response); err != nil { - return fmt.Errorf("failed to encode response: %v", err) +func writeObjectToResponseBody(w http.ResponseWriter, response any) error { + respBody := new(bytes.Buffer) + err := json.NewEncoder(respBody).Encode(response) + if err != nil { + return fmt.Errorf("failed to encode payload: %v", err) + } - } - if _, err := w.Write(reqBodyBytes.Bytes()); err != nil { - return fmt.Errorf("failed to write response: %v", err) - } - return nil - case <-time.After(30 * time.Second): - log.Warn("Config update failed: timeout") - w.WriteHeader(http.StatusRequestTimeout) - return nil - } + _, err = fmt.Fprint(w, respBody) + if err != nil { + return fmt.Errorf("failed to send payload: %v", err) } return nil } diff --git a/src/plugins/agent_api_test.go b/src/plugins/agent_api_test.go index 8c73c4d24..84c41a6bb 100644 --- a/src/plugins/agent_api_test.go +++ b/src/plugins/agent_api_test.go @@ -8,14 +8,19 @@ package plugins import ( + "bytes" "context" "crypto/tls" "crypto/x509" "encoding/json" "fmt" + "io" + "io/fs" "io/ioutil" + "mime/multipart" "net/http" "net/http/httptest" + "path/filepath" "time" "os" @@ -30,9 +35,74 @@ import ( "github.com/nginx/agent/v2/src/core/config" tutils "github.com/nginx/agent/v2/test/utils" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) +const ( + nginxConfigContent = ` + user nginx; + worker_processes auto; + + error_log /usr/local/nginx/error.log notice; + pid /var/run/nginx.pid; + + events { + worker_connections 1024; + } + + + http { + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /usr/local/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + server { + listen 8080; + server_name localhost; + location /api { + stub_status; + allow 127.0.0.1; + deny all; + } + } + } + ` +) + +func TestAgentAPI_Info(t *testing.T) { + agentAPI := AgentAPI{} + info := agentAPI.Info() + + assert.Equal(t, "Agent API Plugin", info.Name()) + assert.Equal(t, "v0.0.1", info.Version()) +} + +func TestAgentAPI_Subscriptions(t *testing.T) { + expectedSubscriptions := []string{ + core.AgentAPIConfigApplyResponse, + core.MetricReport, + core.NginxConfigValidationPending, + core.NginxConfigApplyFailed, + core.NginxConfigApplySucceeded, + } + + agentAPI := AgentAPI{} + subscriptions := agentAPI.Subscriptions() + + assert.Equal(t, expectedSubscriptions, subscriptions) +} + func TestNginxHandler_sendInstanceDetailsPayload(t *testing.T) { tests := []struct { name string @@ -83,7 +153,19 @@ func TestNginxHandler_sendInstanceDetailsPayload(t *testing.T) { path := "/nginx/" req := httptest.NewRequest(http.MethodGet, path, nil) - err := sendInstanceDetailsPayload(tt.nginxDetails, respRec, req) + env := tutils.GetMockEnv() + mockNginxBinary := tutils.NewMockNginxBinary() + processes := []core.Process{} + + for _, nginxDetail := range tt.nginxDetails { + mockNginxBinary.On("GetNginxDetailsFromProcess", mock.Anything).Return(nginxDetail).Once() + processes = append(processes, core.Process{Pid: 1, Name: "12345", IsMaster: true}) + } + + env.On("Processes").Return(processes) + + nginxHandler := NginxHandler{env: env, nginxBinary: mockNginxBinary} + err := nginxHandler.sendInstanceDetailsPayload(respRec, req) assert.NoError(t, err) resp := respRec.Result() @@ -101,22 +183,103 @@ func TestNginxHandler_sendInstanceDetailsPayload(t *testing.T) { } func TestNginxHandler_updateConfig(t *testing.T) { + conf := &proto.NginxConfig{} + tests := []struct { - name string - configUpdate string + name string + configUpdate string + validationTimeout time.Duration + response *proto.Command_NginxConfigResponse + nginxInstancesPresent bool + expectedStatusCode int + expectedMessage string + expectedStatus string }{ { - name: "update config", - configUpdate: "# test", + name: "no nginx instances", + configUpdate: nginxConfigContent, + validationTimeout: 15 * time.Second, + response: nil, + nginxInstancesPresent: false, + expectedStatusCode: 500, + expectedMessage: "No NGINX instances found", + expectedStatus: "", + }, + { + name: "no config apply response", + configUpdate: nginxConfigContent, + validationTimeout: 1 * time.Millisecond, + response: nil, + nginxInstancesPresent: true, + expectedStatusCode: 408, + expectedMessage: "Pending config apply", + expectedStatus: "PENDING", + }, + { + name: "pending config apply response", + configUpdate: nginxConfigContent, + validationTimeout: 15 * time.Second, + response: &proto.Command_NginxConfigResponse{ + NginxConfigResponse: &proto.NginxConfigResponse{ + Status: &proto.CommandStatusResponse{ + Status: proto.CommandStatusResponse_CMD_OK, + Message: configAppliedProcessedResponse, + }, + Action: proto.NginxConfigAction_APPLY, + ConfigData: conf.GetConfigData(), + }, + }, + nginxInstancesPresent: true, + expectedStatusCode: 408, + expectedMessage: "config apply request successfully processed", + expectedStatus: "PENDING", + }, + { + name: "successful config apply response", + configUpdate: nginxConfigContent, + validationTimeout: 15 * time.Second, + response: &proto.Command_NginxConfigResponse{ + NginxConfigResponse: &proto.NginxConfigResponse{ + Status: &proto.CommandStatusResponse{ + Status: proto.CommandStatusResponse_CMD_OK, + Message: configAppliedResponse, + }, + Action: proto.NginxConfigAction_APPLY, + ConfigData: conf.GetConfigData(), + }, + }, + nginxInstancesPresent: true, + expectedStatusCode: 200, + expectedMessage: "config applied successfully", + expectedStatus: "OK", + }, + { + name: "failed config apply response", + configUpdate: nginxConfigContent, + validationTimeout: 15 * time.Second, + response: &proto.Command_NginxConfigResponse{ + NginxConfigResponse: &proto.NginxConfigResponse{ + Status: &proto.CommandStatusResponse{ + Status: proto.CommandStatusResponse_CMD_ERROR, + Message: "config applied failed", + }, + Action: proto.NginxConfigAction_APPLY, + ConfigData: conf.GetConfigData(), + }, + }, + nginxInstancesPresent: true, + expectedStatusCode: 400, + expectedMessage: "config applied failed", + expectedStatus: "ERROR", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - t.Skip() + validationTimeout = tt.validationTimeout w := httptest.NewRecorder() path := "/nginx/config/" - file, err := os.CreateTemp(t.TempDir(), "file") + file, err := os.CreateTemp(t.TempDir(), "nginx.conf") require.NoError(t, err) defer file.Close() @@ -134,21 +297,132 @@ func TestNginxHandler_updateConfig(t *testing.T) { r := httptest.NewRequest(http.MethodPut, path, body) r.Header.Set("Content-Type", writer.FormDataContentType()) + nginxDetail := &proto.NginxDetails{ + NginxId: "1", Version: "21", ConfPath: file.Name(), ProcessId: "123", StartTime: 1238043824, + BuiltFromSource: false, + LoadableModules: []string{}, + RuntimeModules: []string{}, + Plus: &proto.NginxPlusMetaData{Enabled: true}, + ConfigureArgs: []string{}, + } + + var env *tutils.MockEnvironment + if tt.nginxInstancesPresent { + env = tutils.GetMockEnvWithProcess() + } else { + env = tutils.GetMockEnv() + env.On("Processes", mock.Anything).Return([]core.Process{}) + } + env.On("WriteFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil) + + mockNginxBinary := tutils.NewMockNginxBinary() + mockNginxBinary.On("GetNginxDetailsFromProcess", mock.Anything).Return(nginxDetail) + mockNginxBinary.On("ReadConfig", mock.Anything, mock.Anything, mock.Anything).Return(conf, nil) + + pipeline := core.NewMessagePipe(context.TODO()) + h := &NginxHandler{ config: config.Defaults, - env: &core.EnvironmentType{}, - pipeline: core.NewMessagePipe(context.TODO()), - nginxBinary: tutils.NewMockNginxBinary(), + env: env, + pipeline: pipeline, + nginxBinary: mockNginxBinary, responseChannel: make(chan *proto.Command_NginxConfigResponse), } + if tt.response != nil { + go func() { h.responseChannel <- tt.response }() + } + err = h.updateConfig(w, r) assert.NoError(t, err) + assert.Equal(t, tt.expectedStatusCode, w.Result().StatusCode) + resp := w.Result() defer resp.Body.Close() - assert.Equal(t, "# test", w.Body.String()) + if tt.response == nil { + result := &AgentAPIConfigApplyStatusResponse{} + err = json.NewDecoder(w.Body).Decode(result) + assert.NoError(t, err) + assert.Equal(t, tt.expectedMessage, result.Message) + assert.Equal(t, tt.expectedStatus, result.Status) + } else { + result := &AgentAPIConfigApplyResponse{} + err = json.NewDecoder(w.Body).Decode(result) + assert.NoError(t, err) + assert.Equal(t, tt.expectedMessage, result.NginxInstances[0].Message) + assert.Equal(t, tt.expectedStatus, result.NginxInstances[0].Status) + } + + }) + } +} + +func TestNginxHandler_getConfigStatus(t *testing.T) { + tests := []struct { + name string + url string + configResponseStatus *proto.NginxConfigStatus + expectedStatusCode int + expectedMessage string + expectedStatus string + }{ + { + name: "no query parameter", + url: "/nginx/config/status/", + configResponseStatus: nil, + expectedStatusCode: 400, + expectedMessage: "Missing required query parameter correlation_id", + expectedStatus: "UNKNOWN", + }, + { + name: "no matching correlation_id", + url: "/nginx/config/status/?correlation_id=123", + configResponseStatus: nil, + expectedStatusCode: 404, + expectedMessage: "Unable to find a config apply request with the correlation_id 123", + expectedStatus: "UNKNOWN", + }, + { + name: "found matching correlation_id", + url: "/nginx/config/status/?correlation_id=123", + configResponseStatus: &proto.NginxConfigStatus{ + CorrelationId: "123", + Status: proto.NginxConfigStatus_OK, + Message: "config applied successfully", + }, + expectedStatusCode: 200, + expectedMessage: "config applied successfully", + expectedStatus: "OK", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + w := httptest.NewRecorder() + r := httptest.NewRequest(http.MethodGet, tt.url, nil) + h := &NginxHandler{ + config: config.Defaults, + env: tutils.GetMockEnv(), + pipeline: core.NewMessagePipe(context.TODO()), + nginxBinary: tutils.NewMockNginxBinary(), + responseChannel: make(chan *proto.Command_NginxConfigResponse), + configResponseStatus: tt.configResponseStatus, + } + + err := h.getConfigStatus(w, r) + assert.NoError(t, err) + + assert.Equal(t, tt.expectedStatusCode, w.Result().StatusCode) + + resp := w.Result() + defer resp.Body.Close() + + result := &AgentAPIConfigApplyStatusResponse{} + err = json.NewDecoder(w.Body).Decode(result) + assert.NoError(t, err) + assert.Equal(t, tt.expectedMessage, result.Message) + assert.Equal(t, tt.expectedStatus, result.Status) }) } } diff --git a/src/plugins/nginx.go b/src/plugins/nginx.go index 0de2a1b25..e80514a17 100644 --- a/src/plugins/nginx.go +++ b/src/plugins/nginx.go @@ -28,7 +28,9 @@ import ( ) const ( - appProtectMetadataFilePath = "/etc/nms/app_protect_metadata.json" + appProtectMetadataFilePath = "/etc/nms/app_protect_metadata.json" + configAppliedProcessedResponse = "config apply request successfully processed" + configAppliedResponse = "config applied successfully" ) var ( @@ -37,15 +39,15 @@ var ( // Nginx is the metadata of our nginx binary type Nginx struct { - messagePipeline core.MessagePipeInterface - nginxBinary core.NginxBinary - processes []core.Process - env core.Environment - cmdr client.Commander - config *config.Config - isNAPEnabled bool - isConfUploadEnabled bool - configApplyStatusChannel chan *proto.Command_NginxConfigResponse + messagePipeline core.MessagePipeInterface + nginxBinary core.NginxBinary + processes []core.Process + env core.Environment + cmdr client.Commander + config *config.Config + isNAPEnabled bool + isFeatureNginxConfigEnabled bool + configApplyStatusChannel chan *proto.Command_NginxConfigResponse } type ConfigRollbackResponse struct { @@ -72,22 +74,18 @@ type NginxConfigValidationResponse struct { } func NewNginx(cmdr client.Commander, nginxBinary core.NginxBinary, env core.Environment, loadedConfig *config.Config) *Nginx { - var isNAPEnabled bool - if loadedConfig.NginxAppProtect != (config.NginxAppProtect{}) { - isNAPEnabled = true - } - - isConfUploadEnabled := isConfUploadEnabled(loadedConfig) + isNAPEnabled := loadedConfig.IsNginxAppProtectConfigured() + isFeatureNginxConfigEnabled := loadedConfig.IsFeatureEnabled(agent_config.FeatureNginxConfig) return &Nginx{ - nginxBinary: nginxBinary, - processes: env.Processes(), - env: env, - cmdr: cmdr, - config: loadedConfig, - isNAPEnabled: isNAPEnabled, - isConfUploadEnabled: isConfUploadEnabled, - configApplyStatusChannel: make(chan *proto.Command_NginxConfigResponse, 1), + nginxBinary: nginxBinary, + processes: env.Processes(), + env: env, + cmdr: cmdr, + config: loadedConfig, + isNAPEnabled: isNAPEnabled, + isFeatureNginxConfigEnabled: isFeatureNginxConfigEnabled, + configApplyStatusChannel: make(chan *proto.Command_NginxConfigResponse, 1), } } @@ -111,10 +109,11 @@ func (n *Nginx) Process(message *core.Message) { switch cmd := message.Data().(type) { case *proto.Command: n.processCmd(cmd) - case *proto.NginxConfig: - log.Debug("writeConfigAndReloadNginx") - status := n.writeConfigAndReloadNginx("123", cmd) - n.messagePipeline.Process(core.NewMessage(core.RestAPIConfigApplyResponse, status)) + case *AgentAPIConfigApplyRequest: + status := n.writeConfigAndReloadNginx(cmd.correlationId, cmd.config) + if status.NginxConfigResponse.GetStatus().GetMessage() != configAppliedProcessedResponse { + n.messagePipeline.Process(core.NewMessage(core.AgentAPIConfigApplyResponse, status)) + } } case core.NginxConfigUpload: @@ -183,7 +182,7 @@ func (n *Nginx) Subscriptions() []string { func (n *Nginx) uploadConfig(config *proto.ConfigDescriptor, messageId string) error { log.Debugf("Uploading config for %v", config) - if !n.isConfUploadEnabled { + if !n.isFeatureNginxConfigEnabled { log.Info("unable to upload config as nginx-config feature is disabled") return nil } @@ -235,7 +234,7 @@ func (n *Nginx) processCmd(cmd *proto.Command) { switch commandData.NginxConfig.Action { case proto.NginxConfigAction_APPLY: - if n.isConfUploadEnabled { + if n.isFeatureNginxConfigEnabled { status = n.applyConfig(cmd, commandData) } else { log.Warnf("unable to upload config as nginx-config feature is disabled") @@ -269,6 +268,13 @@ func (n *Nginx) processCmd(cmd *proto.Command) { func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) (status *proto.Command_NginxConfigResponse) { log.Debugf("Applying config for message id, %s", cmd.GetMeta().MessageId) + status = &proto.Command_NginxConfigResponse{ + NginxConfigResponse: &proto.NginxConfigResponse{ + Status: newOKStatus(configAppliedProcessedResponse).CmdStatus, + Action: proto.NginxConfigAction_APPLY, + ConfigData: cfg.NginxConfig.ConfigData, + }, + } config, err := n.cmdr.Download(context.Background(), cmd.GetMeta()) if err != nil { @@ -276,45 +282,36 @@ func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) return status } - status = n.writeConfigAndReloadNginx(cmd.Meta.MessageId, config) - - uploadResponse := &proto.Command_NginxConfigResponse{ - NginxConfigResponse: &proto.NginxConfigResponse{ - Action: proto.NginxConfigAction_UNKNOWN, - Status: newOKStatus("config uploaded status").CmdStatus, - ConfigData: nil, - }, - } - - err = n.uploadConfig( - &proto.ConfigDescriptor{ - SystemId: n.env.GetSystemUUID(), - NginxId: config.GetConfigData().GetNginxId(), - }, - cmd.Meta.GetMessageId(), - ) if err != nil { - uploadResponse.NginxConfigResponse.Status = newErrStatus("config uploaded error: " + err.Error()).CmdStatus + status.NginxConfigResponse.Status = newErrStatus("Config apply failed: " + err.Error()).CmdStatus + return status } - uploadResponseCommand := newStatusCommand(cmd) - uploadResponseCommand.Data = uploadResponse - - n.messagePipeline.Process(core.NewMessage(core.CommResponse, uploadResponseCommand)) + status = n.writeConfigAndReloadNginx(cmd.Meta.MessageId, config) log.Debug("Config Apply Complete") return status } -func (n *Nginx) writeConfigAndReloadNginx(messageId string, config *proto.NginxConfig) *proto.Command_NginxConfigResponse { +func (n *Nginx) writeConfigAndReloadNginx(correlationId string, config *proto.NginxConfig) *proto.Command_NginxConfigResponse { status := &proto.Command_NginxConfigResponse{ NginxConfigResponse: &proto.NginxConfigResponse{ - Status: newOKStatus("config applied successfully").CmdStatus, + Status: newOKStatus(configAppliedProcessedResponse).CmdStatus, Action: proto.NginxConfigAction_APPLY, ConfigData: config.ConfigData, }, } + n.messagePipeline.Process(core.NewMessage(core.NginxConfigValidationPending, &proto.AgentActivityStatus{ + Status: &proto.AgentActivityStatus_NginxConfigStatus{ + NginxConfigStatus: &proto.NginxConfigStatus{ + CorrelationId: correlationId, + Status: proto.NginxConfigStatus_PENDING, + Message: "config apply pending", + }, + }, + })) + if config.GetConfigData().GetNginxId() == "" { status.NginxConfigResponse.Status = newErrStatus(fmt.Sprintf("Config apply failed (preflight): no Nginx Id in ConfigDescriptor %v", config.GetConfigData())).CmdStatus return status @@ -344,7 +341,7 @@ func (n *Nginx) writeConfigAndReloadNginx(messageId string, config *proto.NginxC configRollbackResponse := ConfigRollbackResponse{ succeeded: succeeded, - correlationId: messageId, + correlationId: correlationId, timestamp: types.TimestampNow(), nginxDetails: nginx, } @@ -355,57 +352,18 @@ func (n *Nginx) writeConfigAndReloadNginx(messageId string, config *proto.NginxC return n.handleErrorStatus(status, message) } - log.Debug("Validating config") - - err = n.nginxBinary.ValidateConfig(nginx.NginxId, nginx.ProcessPath, nginx.ConfPath, config, configApply) - if err == nil { - _, err = n.nginxBinary.ReadConfig(nginx.GetConfPath(), config.GetConfigData().GetNginxId(), n.env.GetSystemUUID()) - log.Debug("Reading config") - } - if err != nil { - if configApply != nil { - succeeded := true - - if rollbackErr := configApply.Rollback(err); rollbackErr != nil { - log.Errorf("Config rollback failed: %v", rollbackErr) - succeeded = false - } - - configRollbackResponse := ConfigRollbackResponse{ - succeeded: succeeded, - correlationId: messageId, - timestamp: types.TimestampNow(), - nginxDetails: nginx, - } - n.messagePipeline.Process(core.NewMessage(core.ConfigRollbackResponse, configRollbackResponse)) - } + go n.validateConfig(nginx, correlationId, config, configApply) - message := fmt.Sprintf("Config apply failed (write): " + err.Error()) - return n.handleErrorStatus(status, message) - } else if configApply != nil { - if err = configApply.Complete(); err != nil { - log.Errorf("Config complete failed: %v", err) - } - } - - log.Debug("Reloading") - - reloadErr := n.nginxBinary.Reload(nginx.ProcessId, nginx.ProcessPath) - if reloadErr != nil { - status.NginxConfigResponse.Status = newErrStatus("Config apply failed (write): " + reloadErr.Error()).CmdStatus - } - nginxReloadEventMeta := NginxReloadResponse{ - succeeded: reloadErr == nil, - correlationId: messageId, - timestamp: types.TimestampNow(), - nginxDetails: nginx, + // If the NGINX config can be validated with the validationTimeout the result will be returned straight away. + // This is timeout is temporary to ensure we support backwards compatibility. In a future release this timeout + // will be removed. + select { + case result := <-n.configApplyStatusChannel: + return result + case <-time.After(validationTimeout): + log.Errorf("Validation of the NGINX config in taking longer than the validationTimeout %s", validationTimeout) + return status } - n.messagePipeline.Process(core.NewMessage(core.NginxReloadComplete, nginxReloadEventMeta)) - - log.Debug("Enabling file watcher") - n.messagePipeline.Process(core.NewMessage(core.FileWatcherEnabled, true)) - - return status } // This function will run a nginx config validation in a separate go routine. If the validation takes less than 15 seconds then the result is returned straight away, @@ -446,7 +404,7 @@ func (n *Nginx) validateConfig(nginx *proto.NginxDetails, correlationId string, } func (n *Nginx) completeConfigApply(response *NginxConfigValidationResponse) *proto.Command_NginxConfigResponse { - nginxConfigStatusMessage := "Config applied successfully" + nginxConfigStatusMessage := configAppliedResponse if response.configApply != nil { if err := response.configApply.Complete(); err != nil { nginxConfigStatusMessage = fmt.Sprintf("Config complete failed: %v", err) @@ -454,31 +412,35 @@ func (n *Nginx) completeConfigApply(response *NginxConfigValidationResponse) *pr } } - uploadResponse := &proto.Command_NginxConfigResponse{ - NginxConfigResponse: &proto.NginxConfigResponse{ - Action: proto.NginxConfigAction_UNKNOWN, - Status: newOKStatus("config uploaded status").CmdStatus, - ConfigData: nil, - }, - } + // Upload NGINX config only if GPRC server is configured + if n.config.IsGrpcServerConfigured() { + uploadResponse := &proto.Command_NginxConfigResponse{ + NginxConfigResponse: &proto.NginxConfigResponse{ + Action: proto.NginxConfigAction_UNKNOWN, + Status: newOKStatus("config uploaded status").CmdStatus, + ConfigData: nil, + }, + } - err := n.uploadConfig( - &proto.ConfigDescriptor{ - SystemId: n.env.GetSystemUUID(), - NginxId: response.config.GetConfigData().GetNginxId(), - }, - response.correlationId, - ) - if err != nil { - uploadResponse.NginxConfigResponse.Status = newErrStatus("Config uploaded error: " + err.Error()).CmdStatus - nginxConfigStatusMessage = fmt.Sprintf("Config uploaded error: %v", err) - log.Errorf(nginxConfigStatusMessage) - } + err := n.uploadConfig( + &proto.ConfigDescriptor{ + SystemId: n.env.GetSystemUUID(), + NginxId: response.config.GetConfigData().GetNginxId(), + }, + response.correlationId, + ) + if err != nil { + uploadResponse.NginxConfigResponse.Status = newErrStatus("Config uploaded error: " + err.Error()).CmdStatus + nginxConfigStatusMessage = fmt.Sprintf("Config uploaded error: %v", err) + log.Errorf(nginxConfigStatusMessage) + } + + uploadResponseCommand := &proto.Command{Meta: grpc.NewMessageMeta(response.correlationId)} + uploadResponseCommand.Data = uploadResponse - uploadResponseCommand := &proto.Command{Meta: grpc.NewMessageMeta(response.correlationId)} - uploadResponseCommand.Data = uploadResponse + n.messagePipeline.Process(core.NewMessage(core.CommResponse, uploadResponseCommand)) + } - n.messagePipeline.Process(core.NewMessage(core.CommResponse, uploadResponseCommand)) log.Debug("Enabling file watcher") n.messagePipeline.Process(core.NewMessage(core.FileWatcherEnabled, true)) @@ -511,7 +473,7 @@ func (n *Nginx) completeConfigApply(response *NginxConfigValidationResponse) *pr status := &proto.Command_NginxConfigResponse{ NginxConfigResponse: &proto.NginxConfigResponse{ - Status: newOKStatus("config apply request successfully processed").CmdStatus, + Status: newOKStatus(nginxConfigStatusMessage).CmdStatus, Action: proto.NginxConfigAction_APPLY, ConfigData: response.config.ConfigData, }, @@ -617,16 +579,7 @@ func (n *Nginx) syncAgentConfigChange() { n.isNAPEnabled = false } - n.isConfUploadEnabled = isConfUploadEnabled(conf) + n.isFeatureNginxConfigEnabled = conf.IsFeatureEnabled(agent_config.FeatureNginxConfig) n.config = conf } - -func isConfUploadEnabled(conf *config.Config) bool { - for _, feature := range conf.Features { - if feature == agent_config.FeatureNginxConfig { - return true - } - } - return false -} diff --git a/src/plugins/nginx_test.go b/src/plugins/nginx_test.go index bc0cb6a10..253ca900f 100644 --- a/src/plugins/nginx_test.go +++ b/src/plugins/nginx_test.go @@ -245,8 +245,9 @@ func TestNginxConfigApply(t *testing.T) { binary.On("Reload", mock.Anything, mock.Anything).Return(nil) commandClient := tutils.GetMockCommandClient(test.config) + conf := &loadedConfig.Config{Server: loadedConfig.Server{Host: "127.0.0.1", GrpcPort: 9092}, Features: []string{agent_config.FeatureNginxConfig}} - pluginUnderTest := NewNginx(commandClient, binary, env, &loadedConfig.Config{Features: []string{agent_config.FeatureNginxConfig}}) + pluginUnderTest := NewNginx(commandClient, binary, env, conf) messagePipe := core.SetupMockMessagePipe(t, ctx, pluginUnderTest) messagePipe.Process(core.NewMessage(core.CommNginxConfig, cmd)) @@ -313,7 +314,9 @@ func TestUploadConfigs(t *testing.T) { cmdr := tutils.NewMockCommandClient() cmdr.On("Upload", mock.Anything, mock.Anything).Return(nil) - pluginUnderTest := NewNginx(cmdr, binary, env, &loadedConfig.Config{Features: []string{agent_config.FeatureNginxConfig}}) + conf := &loadedConfig.Config{Server: loadedConfig.Server{Host: "127.0.0.1", GrpcPort: 9092}, Features: []string{agent_config.FeatureNginxConfig}} + + pluginUnderTest := NewNginx(cmdr, binary, env, conf) messagePipe := core.SetupMockMessagePipe(t, context.Background(), pluginUnderTest) pluginUnderTest.Init(messagePipe) @@ -416,8 +419,9 @@ func TestNginx_Process_NginxConfigUpload(t *testing.T) { binary.On("ReadConfig", "/var/conf", "12345", "12345678").Return(config, nil) env := tutils.GetMockEnvWithProcess() + conf := &loadedConfig.Config{Server: loadedConfig.Server{Host: "127.0.0.1", GrpcPort: 9092}, Features: []string{agent_config.FeatureNginxConfig}} - pluginUnderTest := NewNginx(cmdr, binary, env, &loadedConfig.Config{Features: []string{agent_config.FeatureNginxConfig}}) + pluginUnderTest := NewNginx(cmdr, binary, env, conf) pluginUnderTest.Process(core.NewMessage(core.NginxConfigUpload, configDesc)) binary.AssertExpectations(t) @@ -478,8 +482,9 @@ func TestNginx_validateConfig(t *testing.T) { binary.On("ReadConfig", mock.Anything, mock.Anything, mock.Anything).Return(&proto.NginxConfig{}, nil) binary.On("GetNginxDetailsMapFromProcesses", env.Processes()).Return((tutils.GetDetailsMap())) binary.On("UpdateNginxDetailsFromProcesses", env.Processes()) + conf := &loadedConfig.Config{Server: loadedConfig.Server{Host: "127.0.0.1", GrpcPort: 9092}, Features: []string{agent_config.FeatureNginxConfig}} - pluginUnderTest := NewNginx(&tutils.MockCommandClient{}, binary, env, &loadedConfig.Config{Features: []string{agent_config.FeatureNginxConfig}}) + pluginUnderTest := NewNginx(&tutils.MockCommandClient{}, binary, env, conf) messagePipe := core.SetupMockMessagePipe(t, context.TODO(), pluginUnderTest) messagePipe.Run() @@ -547,7 +552,9 @@ func TestNginx_completeConfigApply(t *testing.T) { }, ) - pluginUnderTest := NewNginx(commandClient, binary, env, &loadedConfig.Config{Features: []string{agent_config.FeatureNginxConfig}}) + conf := &loadedConfig.Config{Server: loadedConfig.Server{Host: "127.0.0.1", GrpcPort: 9092}, Features: []string{agent_config.FeatureNginxConfig}} + + pluginUnderTest := NewNginx(commandClient, binary, env, conf) dir := t.TempDir() tempConf, err := os.CreateTemp(dir, "nginx.conf") @@ -634,7 +641,9 @@ func TestNginx_rollbackConfigApply(t *testing.T) { }, ) - pluginUnderTest := NewNginx(commandClient, binary, env, &loadedConfig.Config{Features: []string{agent_config.FeatureNginxConfig}}) + conf := &loadedConfig.Config{Server: loadedConfig.Server{Host: "127.0.0.1", GrpcPort: 9092}, Features: []string{agent_config.FeatureNginxConfig}} + + pluginUnderTest := NewNginx(commandClient, binary, env, conf) dir := t.TempDir() tempConf, err := os.CreateTemp(dir, "nginx.conf") diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/core/config/defaults.go b/test/performance/vendor/github.com/nginx/agent/v2/src/core/config/defaults.go index b5f0c9063..722ddcce4 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/core/config/defaults.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/core/config/defaults.go @@ -234,8 +234,8 @@ var ( }, // API Config &IntFlag{ - Name: AgentAPIPort, - Usage: "The desired port to use for nginx-agent to expose for HTTP traffic.", + Name: AgentAPIPort, + Usage: "The desired port to use for nginx-agent to expose for HTTP traffic.", }, &StringFlag{ Name: AgentAPICert, diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/core/config/types.go b/test/performance/vendor/github.com/nginx/agent/v2/src/core/config/types.go index c65dec245..4ced9dcb3 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/core/config/types.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/core/config/types.go @@ -38,6 +38,23 @@ type Config struct { NAPMonitoring NAPMonitoring `mapstructure:"nap_monitoring" yaml:"nap_monitoring,omitempty"` } +func (c *Config) IsGrpcServerConfigured() bool { + return c.Server.Host != "" && c.Server.GrpcPort != 0 +} + +func (c *Config) IsNginxAppProtectConfigured() bool { + return c.NginxAppProtect != (NginxAppProtect{}) +} + +func (c *Config) IsFeatureEnabled(feature string) bool { + for _, configFeature := range c.Features { + if configFeature == feature { + return true + } + } + return false +} + type Server struct { Host string `mapstructure:"host" yaml:"-"` GrpcPort int `mapstructure:"grpcPort" yaml:"-"` diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/core/nginx.go b/test/performance/vendor/github.com/nginx/agent/v2/src/core/nginx.go index 93cd0eca4..4b8f1e747 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/core/nginx.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/core/nginx.go @@ -258,9 +258,11 @@ func (n *NginxBinaryType) ValidateConfig(processId, bin, configLocation string, log.Debugf("Validating config, %s for nginx process, %s", configLocation, processId) response, err := runCmd(bin, "-t", "-c", configLocation) if err != nil { - confFiles, auxFiles, err := sdk.GetNginxConfigFiles(config) - n.writeBackup(config, confFiles, auxFiles) - return fmt.Errorf("error running nginx -t -c %v:\n%s%v", configLocation, response, err) + confFiles, auxFiles, getNginxConfigFilesErr := sdk.GetNginxConfigFiles(config) + if getNginxConfigFilesErr == nil { + n.writeBackup(config, confFiles, auxFiles) + } + return fmt.Errorf("error running nginx -t -c %v:\n%s", configLocation, response) } log.Infof("Config validated:\n%s", response) diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/core/topics.go b/test/performance/vendor/github.com/nginx/agent/v2/src/core/topics.go index d4e64b780..67a6e1ff0 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/core/topics.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/core/topics.go @@ -52,5 +52,5 @@ const ( ConfigRollbackResponse = "config.rollback.response" DataplaneSoftwareDetailsUpdated = "dataplane.software.details.updated" EnableExtension = "enable.extension" - RestAPIConfigApplyResponse = "rest.api.config.apply.response" + AgentAPIConfigApplyResponse = "agent.api.config.apply.response" ) diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go index 2d5229251..33697fcbc 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go @@ -14,9 +14,11 @@ import ( "fmt" "io" "net/http" + "os" "regexp" "time" + "github.com/google/uuid" "github.com/nginx/agent/sdk/v2" "github.com/nginx/agent/sdk/v2/proto" "github.com/nginx/agent/v2/src/core" @@ -27,6 +29,19 @@ import ( log "github.com/sirupsen/logrus" ) +const ( + okStatus = "OK" + pendingStatus = "PENDING" + errorStatus = "ERROR" + unknownStatus = "UNKNOWN" +) + +var ( + instancesRegex = regexp.MustCompile(`^\/nginx[\/]*$`) + configRegex = regexp.MustCompile(`^\/nginx/config[\/]*$`) + configStatusRegex = regexp.MustCompile(`^\/nginx/config/status[\/]*$`) +) + type AgentAPI struct { config *config.Config env core.Environment @@ -38,11 +53,39 @@ type AgentAPI struct { } type NginxHandler struct { - config *config.Config - env core.Environment - pipeline core.MessagePipeInterface - nginxBinary core.NginxBinary - responseChannel chan *proto.Command_NginxConfigResponse + config *config.Config + env core.Environment + pipeline core.MessagePipeInterface + nginxBinary core.NginxBinary + responseChannel chan *proto.Command_NginxConfigResponse + configResponseStatus *proto.NginxConfigStatus +} + +type AgentAPIConfigApplyRequest struct { + correlationId string + config *proto.NginxConfig +} + +type NginxInstanceResponse struct { + NginxId string `json:"nginx_id"` + Message string `json:"message"` + Status string `json:"status"` +} + +type AgentAPIConfigApplyResponse struct { + CorrelationId string `json:"correlation_id"` + NginxInstances []NginxInstanceResponse `json:"nginx_instances"` +} + +type AgentAPICommonResponse struct { + CorrelationId string `json:"correlation_id"` + Message string `json:"message"` +} + +type AgentAPIConfigApplyStatusResponse struct { + CorrelationId string `json:"correlation_id"` + Message string `json:"message"` + Status string `json:"status"` } const ( @@ -50,11 +93,6 @@ const ( jsonMimeType = "application/json" ) -var ( - instancesRegex = regexp.MustCompile(`^\/nginx[\/]*$`) - configRegex = regexp.MustCompile(`^\/nginx/config[\/]*$`) -) - func NewAgentAPI(config *config.Config, env core.Environment, nginxBinary core.NginxBinary) *AgentAPI { return &AgentAPI{ config: config, @@ -81,7 +119,7 @@ func (a *AgentAPI) Process(message *core.Message) { log.Tracef("Process function in the agent_api.go, %s %v", message.Topic(), message.Data()) switch message.Topic() { - case core.RestAPIConfigApplyResponse: + case core.AgentAPIConfigApplyResponse: switch response := message.Data().(type) { case *proto.Command_NginxConfigResponse: a.nginxHandler.responseChannel <- response @@ -95,6 +133,13 @@ func (a *AgentAPI) Process(message *core.Message) { default: log.Warnf("Unknown MetricReport type: %T(%v)", message.Data(), message.Data()) } + case core.NginxConfigValidationPending, core.NginxConfigApplyFailed, core.NginxConfigApplySucceeded: + switch response := message.Data().(type) { + case *proto.AgentActivityStatus: + a.nginxHandler.configResponseStatus = response.GetNginxConfigStatus() + default: + log.Errorf("Expected the type %T but got %T", &proto.AgentActivityStatus{}, response) + } } } func (a *AgentAPI) Info() *core.Info { @@ -102,16 +147,23 @@ func (a *AgentAPI) Info() *core.Info { } func (a *AgentAPI) Subscriptions() []string { - return []string{core.RestAPIConfigApplyResponse, core.MetricReport} + return []string{ + core.AgentAPIConfigApplyResponse, + core.MetricReport, + core.NginxConfigValidationPending, + core.NginxConfigApplyFailed, + core.NginxConfigApplySucceeded, + } } func (a *AgentAPI) createHttpServer() { a.nginxHandler = &NginxHandler{ - config: a.config, - pipeline: a.pipeline, - env: a.env, - nginxBinary: a.nginxBinary, - responseChannel: make(chan *proto.Command_NginxConfigResponse), + config: a.config, + pipeline: a.pipeline, + env: a.env, + nginxBinary: a.nginxBinary, + responseChannel: make(chan *proto.Command_NginxConfigResponse), + configResponseStatus: &proto.NginxConfigStatus{}, } mux := http.NewServeMux() @@ -121,7 +173,7 @@ func (a *AgentAPI) createHttpServer() { registerer.MustRegister(a.exporter) mux.Handle("/metrics", promhttp.HandlerFor(gatherer, promhttp.HandlerOpts{})) mux.Handle("/nginx/", a.nginxHandler) - + a.server = http.Server{ Addr: fmt.Sprintf(":%d", a.config.AgentAPI.Port), Handler: mux, @@ -151,7 +203,7 @@ func (h *NginxHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - err := sendInstanceDetailsPayload(h.getNginxDetails(), w, r) + err := h.sendInstanceDetailsPayload(w, r) if err != nil { log.Warnf("Failed to send instance details payload: %v", err) } @@ -165,6 +217,16 @@ func (h *NginxHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err != nil { log.Warnf("Failed to update config: %v", err) } + case configStatusRegex.MatchString(r.URL.Path): + if r.Method != http.MethodGet { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + + err := h.getConfigStatus(w, r) + if err != nil { + log.Warnf("Failed to get config status: %v", err) + } default: w.WriteHeader(http.StatusNotFound) _, err := fmt.Fprint(w, []byte("not found")) @@ -174,7 +236,8 @@ func (h *NginxHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } -func sendInstanceDetailsPayload(nginxDetails []*proto.NginxDetails, w http.ResponseWriter, r *http.Request) error { +func (h *NginxHandler) sendInstanceDetailsPayload(w http.ResponseWriter, r *http.Request) error { + nginxDetails := h.getNginxDetails() w.WriteHeader(http.StatusOK) if len(nginxDetails) == 0 { @@ -187,20 +250,108 @@ func sendInstanceDetailsPayload(nginxDetails []*proto.NginxDetails, w http.Respo return nil } - respBody := new(bytes.Buffer) - err := json.NewEncoder(respBody).Encode(nginxDetails) + return writeObjectToResponseBody(w, nginxDetails) +} + +func (h *NginxHandler) updateConfig(w http.ResponseWriter, r *http.Request) error { + correlationId := uuid.New().String() + + buf, err := readFileFromRequest(r) if err != nil { - return fmt.Errorf("failed to encode payload: %v", err) + w.WriteHeader(http.StatusBadRequest) + response := AgentAPICommonResponse{ + CorrelationId: correlationId, + Message: err.Error(), + } + return writeObjectToResponseBody(w, response) } - _, err = fmt.Fprint(w, respBody) - if err != nil { - return fmt.Errorf("failed to send payload: %v", err) + nginxDetails := h.getNginxDetails() + + for _, nginxDetail := range nginxDetails { + err := h.applyNginxConfig(nginxDetail, buf, correlationId) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + response := AgentAPICommonResponse{ + CorrelationId: correlationId, + Message: err.Error(), + } + return writeObjectToResponseBody(w, response) + } + } + + if len(nginxDetails) > 0 { + agentAPIConfigApplyResponse := &AgentAPIConfigApplyResponse{CorrelationId: correlationId, NginxInstances: make([]NginxInstanceResponse, 0)} + + select { + case response := <-h.responseChannel: + nginxResponse := NginxInstanceResponse{ + NginxId: response.NginxConfigResponse.GetConfigData().GetNginxId(), + Message: response.NginxConfigResponse.GetStatus().GetMessage(), + Status: okStatus, + } + + if response.NginxConfigResponse.GetStatus().GetStatus() != proto.CommandStatusResponse_CMD_OK { + w.WriteHeader(http.StatusBadRequest) + nginxResponse.Status = errorStatus + } else { + if response.NginxConfigResponse.GetStatus().GetMessage() == configAppliedProcessedResponse { + w.WriteHeader(http.StatusRequestTimeout) + nginxResponse.Status = pendingStatus + } else { + w.WriteHeader(http.StatusOK) + } + } + + agentAPIConfigApplyResponse.NginxInstances = append(agentAPIConfigApplyResponse.NginxInstances, nginxResponse) + + // If the number of responses match the number of NGINX instances then return a response. + // Otherwise wait until all config apply requests are complete for all NGINX instances. + if len(agentAPIConfigApplyResponse.NginxInstances) == len(nginxDetails) { + return writeObjectToResponseBody(w, agentAPIConfigApplyResponse) + } + + case <-time.After(validationTimeout): + w.WriteHeader(http.StatusRequestTimeout) + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ + CorrelationId: correlationId, + Message: "Pending config apply", + Status: pendingStatus, + } + + return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) + } + } else { + w.WriteHeader(http.StatusInternalServerError) + response := AgentAPICommonResponse{ + CorrelationId: correlationId, + Message: "No NGINX instances found", + } + return writeObjectToResponseBody(w, response) } + w.WriteHeader(http.StatusInternalServerError) return nil } +func readFileFromRequest(r *http.Request) (*bytes.Buffer, error) { + err := r.ParseMultipartForm(32 << 20) + if err != nil { + log.Errorf("unable to parse config apply request, %v", err) + } + file, _, err := r.FormFile("file") + if err != nil { + return nil, fmt.Errorf("can't read form file: %v", err) + } + defer file.Close() + + buf := bytes.NewBuffer(nil) + if _, err := io.Copy(buf, file); err != nil { + return nil, fmt.Errorf("can't read file, %v", err) + } + return buf, nil +} + func (h *NginxHandler) getNginxDetails() []*proto.NginxDetails { var nginxDetails []*proto.NginxDetails @@ -212,86 +363,99 @@ func (h *NginxHandler) getNginxDetails() []*proto.NginxDetails { return nginxDetails } -func (h *NginxHandler) updateConfig(w http.ResponseWriter, r *http.Request) error { - log.Info("Updating config") +func (h *NginxHandler) applyNginxConfig(nginxDetail *proto.NginxDetails, buf *bytes.Buffer, correlationId string) error { + fullFilePath := nginxDetail.ConfPath - err := r.ParseMultipartForm(32 << 20) + // Create backup of nginx.conf file on host + data, err := os.ReadFile(fullFilePath) if err != nil { - log.Errorf("unable to parse config apply request, %v", err) + return fmt.Errorf("unable to read file %s: %v", fullFilePath, err) + } + + protoFile := &proto.File{ + Name: fullFilePath, + Permissions: "0755", + Contents: buf.Bytes(), } - file, fileHeader, err := r.FormFile("file") + + configApply, err := sdk.NewConfigApply(protoFile.GetName(), h.config.AllowedDirectoriesMap) if err != nil { - return fmt.Errorf("can't read form file: %v", err) + return fmt.Errorf("unable to write config: %v", err) } - defer file.Close() - nginxDetails := h.getNginxDetails() + // Temporarily write the new nginx.conf to disk + err = h.env.WriteFiles(configApply, []*proto.File{protoFile}, "", h.config.AllowedDirectoriesMap) + if err != nil { + rollbackErr := configApply.Rollback(err) + return fmt.Errorf("config rollback failed: %v", rollbackErr) + } - log.Debug("Updating instances") + // Create NginxConfig object for new nginx.conf + conf, err := h.nginxBinary.ReadConfig(fullFilePath, nginxDetail.NginxId, h.env.GetSystemUUID()) + if err != nil { + rollbackErr := configApply.Rollback(err) + return fmt.Errorf("unable to read config: %v", rollbackErr) + } - for _, nginxDetail := range nginxDetails { - buf := bytes.NewBuffer(nil) - if _, err := io.Copy(buf, file); err != nil { - return fmt.Errorf("can't read file, %v", err) - } + // Write back the original nginx.conf + err = os.WriteFile(fullFilePath, data, 0644) + if err != nil { + rollbackErr := configApply.Rollback(err) + return fmt.Errorf("unable to write file %s: %v", fullFilePath, rollbackErr) + } - fullFilePath := nginxDetail.ConfPath + // Send a config apply request to the nginx.go plugin + h.pipeline.Process(core.NewMessage(core.CommNginxConfig, &AgentAPIConfigApplyRequest{correlationId: correlationId, config: conf})) + return nil +} - protoFile := &proto.File{ - Name: fullFilePath, - Permissions: "0755", - Contents: buf.Bytes(), - } +func (h *NginxHandler) getConfigStatus(w http.ResponseWriter, r *http.Request) error { + correlationId := r.URL.Query().Get("correlation_id") - log.Tracef("protoFile: %v", protoFile) + if correlationId == "" { + w.WriteHeader(http.StatusBadRequest) - configApply, err := sdk.NewConfigApply(protoFile.GetName(), h.config.AllowedDirectoriesMap) - if err != nil { - return fmt.Errorf("unable to write config: %v", err) + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ + CorrelationId: correlationId, + Message: "Missing required query parameter correlation_id", + Status: unknownStatus, } - log.Debug("Writing config") - - err = h.env.WriteFiles(configApply, []*proto.File{protoFile}, "", h.config.AllowedDirectoriesMap) - if err != nil { - rollbackErr := configApply.Rollback(err) - return fmt.Errorf("config rollback failed: %v", rollbackErr) - } + return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) + } - err = configApply.Complete() - if err != nil { - return fmt.Errorf("unable to write config: %v", err) + if h.configResponseStatus.GetCorrelationId() != correlationId { + w.WriteHeader(http.StatusNotFound) + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ + CorrelationId: correlationId, + Message: fmt.Sprintf("Unable to find a config apply request with the correlation_id %s", correlationId), + Status: unknownStatus, } - log.Debug("File written") + return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) + } - conf, err := h.nginxBinary.ReadConfig(fullFilePath, nginxDetail.NginxId, h.env.GetSystemUUID()) - if err != nil { - return fmt.Errorf("unable to read config: %v", err) - } + w.WriteHeader(http.StatusOK) - log.Debug("ReadConfig") + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ + CorrelationId: correlationId, + Message: h.configResponseStatus.Message, + Status: h.configResponseStatus.Status.String(), + } - h.pipeline.Process(core.NewMessage(core.CommNginxConfig, conf)) + return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) +} - log.Debug("Waiting for response or timeout") - select { - case response := <-h.responseChannel: - fmt.Fprintf(w, "%v", fileHeader.Header) - reqBodyBytes := new(bytes.Buffer) - if err := json.NewEncoder(reqBodyBytes).Encode(response); err != nil { - return fmt.Errorf("failed to encode response: %v", err) +func writeObjectToResponseBody(w http.ResponseWriter, response any) error { + respBody := new(bytes.Buffer) + err := json.NewEncoder(respBody).Encode(response) + if err != nil { + return fmt.Errorf("failed to encode payload: %v", err) + } - } - if _, err := w.Write(reqBodyBytes.Bytes()); err != nil { - return fmt.Errorf("failed to write response: %v", err) - } - return nil - case <-time.After(30 * time.Second): - log.Warn("Config update failed: timeout") - w.WriteHeader(http.StatusRequestTimeout) - return nil - } + _, err = fmt.Fprint(w, respBody) + if err != nil { + return fmt.Errorf("failed to send payload: %v", err) } return nil } diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go index 0de2a1b25..e80514a17 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go @@ -28,7 +28,9 @@ import ( ) const ( - appProtectMetadataFilePath = "/etc/nms/app_protect_metadata.json" + appProtectMetadataFilePath = "/etc/nms/app_protect_metadata.json" + configAppliedProcessedResponse = "config apply request successfully processed" + configAppliedResponse = "config applied successfully" ) var ( @@ -37,15 +39,15 @@ var ( // Nginx is the metadata of our nginx binary type Nginx struct { - messagePipeline core.MessagePipeInterface - nginxBinary core.NginxBinary - processes []core.Process - env core.Environment - cmdr client.Commander - config *config.Config - isNAPEnabled bool - isConfUploadEnabled bool - configApplyStatusChannel chan *proto.Command_NginxConfigResponse + messagePipeline core.MessagePipeInterface + nginxBinary core.NginxBinary + processes []core.Process + env core.Environment + cmdr client.Commander + config *config.Config + isNAPEnabled bool + isFeatureNginxConfigEnabled bool + configApplyStatusChannel chan *proto.Command_NginxConfigResponse } type ConfigRollbackResponse struct { @@ -72,22 +74,18 @@ type NginxConfigValidationResponse struct { } func NewNginx(cmdr client.Commander, nginxBinary core.NginxBinary, env core.Environment, loadedConfig *config.Config) *Nginx { - var isNAPEnabled bool - if loadedConfig.NginxAppProtect != (config.NginxAppProtect{}) { - isNAPEnabled = true - } - - isConfUploadEnabled := isConfUploadEnabled(loadedConfig) + isNAPEnabled := loadedConfig.IsNginxAppProtectConfigured() + isFeatureNginxConfigEnabled := loadedConfig.IsFeatureEnabled(agent_config.FeatureNginxConfig) return &Nginx{ - nginxBinary: nginxBinary, - processes: env.Processes(), - env: env, - cmdr: cmdr, - config: loadedConfig, - isNAPEnabled: isNAPEnabled, - isConfUploadEnabled: isConfUploadEnabled, - configApplyStatusChannel: make(chan *proto.Command_NginxConfigResponse, 1), + nginxBinary: nginxBinary, + processes: env.Processes(), + env: env, + cmdr: cmdr, + config: loadedConfig, + isNAPEnabled: isNAPEnabled, + isFeatureNginxConfigEnabled: isFeatureNginxConfigEnabled, + configApplyStatusChannel: make(chan *proto.Command_NginxConfigResponse, 1), } } @@ -111,10 +109,11 @@ func (n *Nginx) Process(message *core.Message) { switch cmd := message.Data().(type) { case *proto.Command: n.processCmd(cmd) - case *proto.NginxConfig: - log.Debug("writeConfigAndReloadNginx") - status := n.writeConfigAndReloadNginx("123", cmd) - n.messagePipeline.Process(core.NewMessage(core.RestAPIConfigApplyResponse, status)) + case *AgentAPIConfigApplyRequest: + status := n.writeConfigAndReloadNginx(cmd.correlationId, cmd.config) + if status.NginxConfigResponse.GetStatus().GetMessage() != configAppliedProcessedResponse { + n.messagePipeline.Process(core.NewMessage(core.AgentAPIConfigApplyResponse, status)) + } } case core.NginxConfigUpload: @@ -183,7 +182,7 @@ func (n *Nginx) Subscriptions() []string { func (n *Nginx) uploadConfig(config *proto.ConfigDescriptor, messageId string) error { log.Debugf("Uploading config for %v", config) - if !n.isConfUploadEnabled { + if !n.isFeatureNginxConfigEnabled { log.Info("unable to upload config as nginx-config feature is disabled") return nil } @@ -235,7 +234,7 @@ func (n *Nginx) processCmd(cmd *proto.Command) { switch commandData.NginxConfig.Action { case proto.NginxConfigAction_APPLY: - if n.isConfUploadEnabled { + if n.isFeatureNginxConfigEnabled { status = n.applyConfig(cmd, commandData) } else { log.Warnf("unable to upload config as nginx-config feature is disabled") @@ -269,6 +268,13 @@ func (n *Nginx) processCmd(cmd *proto.Command) { func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) (status *proto.Command_NginxConfigResponse) { log.Debugf("Applying config for message id, %s", cmd.GetMeta().MessageId) + status = &proto.Command_NginxConfigResponse{ + NginxConfigResponse: &proto.NginxConfigResponse{ + Status: newOKStatus(configAppliedProcessedResponse).CmdStatus, + Action: proto.NginxConfigAction_APPLY, + ConfigData: cfg.NginxConfig.ConfigData, + }, + } config, err := n.cmdr.Download(context.Background(), cmd.GetMeta()) if err != nil { @@ -276,45 +282,36 @@ func (n *Nginx) applyConfig(cmd *proto.Command, cfg *proto.Command_NginxConfig) return status } - status = n.writeConfigAndReloadNginx(cmd.Meta.MessageId, config) - - uploadResponse := &proto.Command_NginxConfigResponse{ - NginxConfigResponse: &proto.NginxConfigResponse{ - Action: proto.NginxConfigAction_UNKNOWN, - Status: newOKStatus("config uploaded status").CmdStatus, - ConfigData: nil, - }, - } - - err = n.uploadConfig( - &proto.ConfigDescriptor{ - SystemId: n.env.GetSystemUUID(), - NginxId: config.GetConfigData().GetNginxId(), - }, - cmd.Meta.GetMessageId(), - ) if err != nil { - uploadResponse.NginxConfigResponse.Status = newErrStatus("config uploaded error: " + err.Error()).CmdStatus + status.NginxConfigResponse.Status = newErrStatus("Config apply failed: " + err.Error()).CmdStatus + return status } - uploadResponseCommand := newStatusCommand(cmd) - uploadResponseCommand.Data = uploadResponse - - n.messagePipeline.Process(core.NewMessage(core.CommResponse, uploadResponseCommand)) + status = n.writeConfigAndReloadNginx(cmd.Meta.MessageId, config) log.Debug("Config Apply Complete") return status } -func (n *Nginx) writeConfigAndReloadNginx(messageId string, config *proto.NginxConfig) *proto.Command_NginxConfigResponse { +func (n *Nginx) writeConfigAndReloadNginx(correlationId string, config *proto.NginxConfig) *proto.Command_NginxConfigResponse { status := &proto.Command_NginxConfigResponse{ NginxConfigResponse: &proto.NginxConfigResponse{ - Status: newOKStatus("config applied successfully").CmdStatus, + Status: newOKStatus(configAppliedProcessedResponse).CmdStatus, Action: proto.NginxConfigAction_APPLY, ConfigData: config.ConfigData, }, } + n.messagePipeline.Process(core.NewMessage(core.NginxConfigValidationPending, &proto.AgentActivityStatus{ + Status: &proto.AgentActivityStatus_NginxConfigStatus{ + NginxConfigStatus: &proto.NginxConfigStatus{ + CorrelationId: correlationId, + Status: proto.NginxConfigStatus_PENDING, + Message: "config apply pending", + }, + }, + })) + if config.GetConfigData().GetNginxId() == "" { status.NginxConfigResponse.Status = newErrStatus(fmt.Sprintf("Config apply failed (preflight): no Nginx Id in ConfigDescriptor %v", config.GetConfigData())).CmdStatus return status @@ -344,7 +341,7 @@ func (n *Nginx) writeConfigAndReloadNginx(messageId string, config *proto.NginxC configRollbackResponse := ConfigRollbackResponse{ succeeded: succeeded, - correlationId: messageId, + correlationId: correlationId, timestamp: types.TimestampNow(), nginxDetails: nginx, } @@ -355,57 +352,18 @@ func (n *Nginx) writeConfigAndReloadNginx(messageId string, config *proto.NginxC return n.handleErrorStatus(status, message) } - log.Debug("Validating config") - - err = n.nginxBinary.ValidateConfig(nginx.NginxId, nginx.ProcessPath, nginx.ConfPath, config, configApply) - if err == nil { - _, err = n.nginxBinary.ReadConfig(nginx.GetConfPath(), config.GetConfigData().GetNginxId(), n.env.GetSystemUUID()) - log.Debug("Reading config") - } - if err != nil { - if configApply != nil { - succeeded := true - - if rollbackErr := configApply.Rollback(err); rollbackErr != nil { - log.Errorf("Config rollback failed: %v", rollbackErr) - succeeded = false - } - - configRollbackResponse := ConfigRollbackResponse{ - succeeded: succeeded, - correlationId: messageId, - timestamp: types.TimestampNow(), - nginxDetails: nginx, - } - n.messagePipeline.Process(core.NewMessage(core.ConfigRollbackResponse, configRollbackResponse)) - } + go n.validateConfig(nginx, correlationId, config, configApply) - message := fmt.Sprintf("Config apply failed (write): " + err.Error()) - return n.handleErrorStatus(status, message) - } else if configApply != nil { - if err = configApply.Complete(); err != nil { - log.Errorf("Config complete failed: %v", err) - } - } - - log.Debug("Reloading") - - reloadErr := n.nginxBinary.Reload(nginx.ProcessId, nginx.ProcessPath) - if reloadErr != nil { - status.NginxConfigResponse.Status = newErrStatus("Config apply failed (write): " + reloadErr.Error()).CmdStatus - } - nginxReloadEventMeta := NginxReloadResponse{ - succeeded: reloadErr == nil, - correlationId: messageId, - timestamp: types.TimestampNow(), - nginxDetails: nginx, + // If the NGINX config can be validated with the validationTimeout the result will be returned straight away. + // This is timeout is temporary to ensure we support backwards compatibility. In a future release this timeout + // will be removed. + select { + case result := <-n.configApplyStatusChannel: + return result + case <-time.After(validationTimeout): + log.Errorf("Validation of the NGINX config in taking longer than the validationTimeout %s", validationTimeout) + return status } - n.messagePipeline.Process(core.NewMessage(core.NginxReloadComplete, nginxReloadEventMeta)) - - log.Debug("Enabling file watcher") - n.messagePipeline.Process(core.NewMessage(core.FileWatcherEnabled, true)) - - return status } // This function will run a nginx config validation in a separate go routine. If the validation takes less than 15 seconds then the result is returned straight away, @@ -446,7 +404,7 @@ func (n *Nginx) validateConfig(nginx *proto.NginxDetails, correlationId string, } func (n *Nginx) completeConfigApply(response *NginxConfigValidationResponse) *proto.Command_NginxConfigResponse { - nginxConfigStatusMessage := "Config applied successfully" + nginxConfigStatusMessage := configAppliedResponse if response.configApply != nil { if err := response.configApply.Complete(); err != nil { nginxConfigStatusMessage = fmt.Sprintf("Config complete failed: %v", err) @@ -454,31 +412,35 @@ func (n *Nginx) completeConfigApply(response *NginxConfigValidationResponse) *pr } } - uploadResponse := &proto.Command_NginxConfigResponse{ - NginxConfigResponse: &proto.NginxConfigResponse{ - Action: proto.NginxConfigAction_UNKNOWN, - Status: newOKStatus("config uploaded status").CmdStatus, - ConfigData: nil, - }, - } + // Upload NGINX config only if GPRC server is configured + if n.config.IsGrpcServerConfigured() { + uploadResponse := &proto.Command_NginxConfigResponse{ + NginxConfigResponse: &proto.NginxConfigResponse{ + Action: proto.NginxConfigAction_UNKNOWN, + Status: newOKStatus("config uploaded status").CmdStatus, + ConfigData: nil, + }, + } - err := n.uploadConfig( - &proto.ConfigDescriptor{ - SystemId: n.env.GetSystemUUID(), - NginxId: response.config.GetConfigData().GetNginxId(), - }, - response.correlationId, - ) - if err != nil { - uploadResponse.NginxConfigResponse.Status = newErrStatus("Config uploaded error: " + err.Error()).CmdStatus - nginxConfigStatusMessage = fmt.Sprintf("Config uploaded error: %v", err) - log.Errorf(nginxConfigStatusMessage) - } + err := n.uploadConfig( + &proto.ConfigDescriptor{ + SystemId: n.env.GetSystemUUID(), + NginxId: response.config.GetConfigData().GetNginxId(), + }, + response.correlationId, + ) + if err != nil { + uploadResponse.NginxConfigResponse.Status = newErrStatus("Config uploaded error: " + err.Error()).CmdStatus + nginxConfigStatusMessage = fmt.Sprintf("Config uploaded error: %v", err) + log.Errorf(nginxConfigStatusMessage) + } + + uploadResponseCommand := &proto.Command{Meta: grpc.NewMessageMeta(response.correlationId)} + uploadResponseCommand.Data = uploadResponse - uploadResponseCommand := &proto.Command{Meta: grpc.NewMessageMeta(response.correlationId)} - uploadResponseCommand.Data = uploadResponse + n.messagePipeline.Process(core.NewMessage(core.CommResponse, uploadResponseCommand)) + } - n.messagePipeline.Process(core.NewMessage(core.CommResponse, uploadResponseCommand)) log.Debug("Enabling file watcher") n.messagePipeline.Process(core.NewMessage(core.FileWatcherEnabled, true)) @@ -511,7 +473,7 @@ func (n *Nginx) completeConfigApply(response *NginxConfigValidationResponse) *pr status := &proto.Command_NginxConfigResponse{ NginxConfigResponse: &proto.NginxConfigResponse{ - Status: newOKStatus("config apply request successfully processed").CmdStatus, + Status: newOKStatus(nginxConfigStatusMessage).CmdStatus, Action: proto.NginxConfigAction_APPLY, ConfigData: response.config.ConfigData, }, @@ -617,16 +579,7 @@ func (n *Nginx) syncAgentConfigChange() { n.isNAPEnabled = false } - n.isConfUploadEnabled = isConfUploadEnabled(conf) + n.isFeatureNginxConfigEnabled = conf.IsFeatureEnabled(agent_config.FeatureNginxConfig) n.config = conf } - -func isConfUploadEnabled(conf *config.Config) bool { - for _, feature := range conf.Features { - if feature == agent_config.FeatureNginxConfig { - return true - } - } - return false -} From 56aa119d73619e3dbd80f4f5b4114d91b20ff522 Mon Sep 17 00:00:00 2001 From: dhurley Date: Mon, 5 Dec 2022 15:27:32 +0000 Subject: [PATCH 4/8] Update GOLANGCI_LINT_VERSION --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d4bf4a7c..2dcb54d46 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: push: env: - GOLANGCI_LINT_VERSION: 'v1.49.0' + GOLANGCI_LINT_VERSION: 'v1.50.1' NFPM_VERSION: 'v2.18.1' jobs: From 9341fe59518acfe5a5a91e809b7eea69eb973c27 Mon Sep 17 00:00:00 2001 From: dhurley Date: Mon, 5 Dec 2022 15:34:52 +0000 Subject: [PATCH 5/8] Update linting in ci.yml --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2dcb54d46..d5fff8546 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,9 @@ jobs: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version-file: 'go.mod' - name: Lint Agent Code uses: golangci/golangci-lint-action@v3 with: From 75950878a5c6b152e473e315d22a89cefaf95b6e Mon Sep 17 00:00:00 2001 From: dhurley Date: Tue, 6 Dec 2022 11:41:05 +0000 Subject: [PATCH 6/8] Clean up test data in unit test --- src/plugins/agent_api_test.go | 41 +------------------ .../nginx/agent/v2/test/utils/nginx.go | 41 +++++++++++++++++++ test/utils/nginx.go | 41 +++++++++++++++++++ 3 files changed, 84 insertions(+), 39 deletions(-) diff --git a/src/plugins/agent_api_test.go b/src/plugins/agent_api_test.go index 84c41a6bb..87d97fbc3 100644 --- a/src/plugins/agent_api_test.go +++ b/src/plugins/agent_api_test.go @@ -39,45 +39,8 @@ import ( "github.com/stretchr/testify/require" ) -const ( - nginxConfigContent = ` - user nginx; - worker_processes auto; - - error_log /usr/local/nginx/error.log notice; - pid /var/run/nginx.pid; - - events { - worker_connections 1024; - } - - - http { - default_type application/octet-stream; - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /usr/local/nginx/access.log main; - - sendfile on; - #tcp_nopush on; - - keepalive_timeout 65; - - #gzip on; - server { - listen 8080; - server_name localhost; - location /api { - stub_status; - allow 127.0.0.1; - deny all; - } - } - } - ` +var ( + nginxConfigContent = tutils.GetDetailsNginxOssConfig() ) func TestAgentAPI_Info(t *testing.T) { diff --git a/test/performance/vendor/github.com/nginx/agent/v2/test/utils/nginx.go b/test/performance/vendor/github.com/nginx/agent/v2/test/utils/nginx.go index e0105ddcc..2b614ef7a 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/test/utils/nginx.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/test/utils/nginx.go @@ -128,3 +128,44 @@ func NewMockNginxBinary() *MockNginxBinary { } var _ core.NginxBinary = NewMockNginxBinary() + +func GetDetailsNginxOssConfig() string { + return ` + user nginx; + worker_processes auto; + + error_log /usr/local/nginx/error.log notice; + pid /var/run/nginx.pid; + + events { + worker_connections 1024; + } + + + http { + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /usr/local/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + server { + listen 8080; + server_name localhost; + location /api { + stub_status; + allow 127.0.0.1; + deny all; + } + } + } + ` +} diff --git a/test/utils/nginx.go b/test/utils/nginx.go index e0105ddcc..2b614ef7a 100644 --- a/test/utils/nginx.go +++ b/test/utils/nginx.go @@ -128,3 +128,44 @@ func NewMockNginxBinary() *MockNginxBinary { } var _ core.NginxBinary = NewMockNginxBinary() + +func GetDetailsNginxOssConfig() string { + return ` + user nginx; + worker_processes auto; + + error_log /usr/local/nginx/error.log notice; + pid /var/run/nginx.pid; + + events { + worker_connections 1024; + } + + + http { + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /usr/local/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + server { + listen 8080; + server_name localhost; + location /api { + stub_status; + allow 127.0.0.1; + deny all; + } + } + } + ` +} From 70135ccd6bc81aa9546665943da5f63bf929ece5 Mon Sep 17 00:00:00 2001 From: dhurley Date: Thu, 8 Dec 2022 17:31:56 +0000 Subject: [PATCH 7/8] Update response for nginx config status endpoint to include nginx id --- sdk/proto/command.pb.go | 245 +++++++++++------- sdk/proto/command.proto | 1 + sdk/proto/events/event.pb.go | 1 + src/plugins/agent_api.go | 53 ++-- src/plugins/agent_api_test.go | 79 +++--- src/plugins/dataplane_status.go | 106 ++++---- src/plugins/dataplane_status_test.go | 4 +- src/plugins/nginx.go | 3 + .../nginx/agent/sdk/v2/proto/command.pb.go | 245 +++++++++++------- .../nginx/agent/sdk/v2/proto/command.proto | 1 + .../agent/sdk/v2/proto/events/event.pb.go | 1 + .../nginx/agent/v2/src/plugins/agent_api.go | 53 ++-- .../agent/v2/src/plugins/dataplane_status.go | 106 ++++---- .../nginx/agent/v2/src/plugins/nginx.go | 3 + .../nginx/agent/sdk/v2/proto/command.pb.go | 245 +++++++++++------- .../nginx/agent/sdk/v2/proto/command.proto | 1 + .../agent/sdk/v2/proto/events/event.pb.go | 1 + 17 files changed, 657 insertions(+), 491 deletions(-) diff --git a/sdk/proto/command.pb.go b/sdk/proto/command.pb.go index 9cd0046a2..1eb5da172 100644 --- a/sdk/proto/command.pb.go +++ b/sdk/proto/command.pb.go @@ -631,6 +631,7 @@ type NginxConfigStatus struct { CorrelationId string `protobuf:"bytes,1,opt,name=correlation_id,json=correlationId,proto3" json:"correlation_id"` Status NginxConfigStatus_Status `protobuf:"varint,2,opt,name=status,proto3,enum=f5.nginx.agent.sdk.NginxConfigStatus_Status" json:"status"` Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message"` + NginxId string `protobuf:"bytes,4,opt,name=nginx_id,json=nginxId,proto3" json:"nginx_id"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -690,6 +691,13 @@ func (m *NginxConfigStatus) GetMessage() string { return "" } +func (m *NginxConfigStatus) GetNginxId() string { + if m != nil { + return m.NginxId + } + return "" +} + type DataplaneSoftwareHealth struct { // Types that are valid to be assigned to Health: // *DataplaneSoftwareHealth_NginxHealth @@ -1253,103 +1261,103 @@ func init() { func init() { proto.RegisterFile("command.proto", fileDescriptor_213c0bb044472049) } var fileDescriptor_213c0bb044472049 = []byte{ - // 1521 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4d, 0x6f, 0xdb, 0xc6, - 0x16, 0x25, 0x15, 0xeb, 0xeb, 0x4a, 0xb6, 0x95, 0xb1, 0x93, 0x28, 0x46, 0x60, 0x1a, 0x7c, 0x2f, - 0x2f, 0xce, 0x7b, 0x79, 0x12, 0xea, 0xa0, 0x08, 0x9a, 0xac, 0x24, 0x4b, 0x09, 0x85, 0xc4, 0x92, - 0x31, 0x89, 0x13, 0x20, 0x45, 0x21, 0x30, 0xe2, 0x48, 0x16, 0x6c, 0x91, 0x2c, 0x49, 0x39, 0x71, - 0xd0, 0x7d, 0xd1, 0xa2, 0x9b, 0x2e, 0xba, 0x28, 0xfa, 0x23, 0xfa, 0x37, 0xba, 0xcc, 0xba, 0x0b, - 0xa2, 0xc8, 0x92, 0xbb, 0x6e, 0xda, 0x45, 0x37, 0xc5, 0x7c, 0x50, 0xa2, 0x24, 0x4a, 0x76, 0xea, - 0xa2, 0x1b, 0xce, 0x70, 0x78, 0xee, 0xb9, 0x77, 0xee, 0xcc, 0x9c, 0xb9, 0x12, 0x2c, 0x77, 0xac, - 0xc1, 0x40, 0x37, 0x8d, 0x92, 0xed, 0x58, 0x9e, 0x85, 0x50, 0xf7, 0xe3, 0x92, 0xd9, 0xeb, 0x9b, - 0x6f, 0x4a, 0x7a, 0x8f, 0x98, 0x5e, 0xc9, 0x35, 0x8e, 0x36, 0xa0, 0x67, 0xf5, 0x2c, 0xfe, 0x7d, - 0x23, 0x4f, 0xe1, 0x96, 0x29, 0xde, 0x72, 0x1c, 0xc4, 0x5f, 0xe0, 0xd0, 0x72, 0xc3, 0x7e, 0x8e, - 0x73, 0x8c, 0x6c, 0xcc, 0x6e, 0xbf, 0x27, 0xde, 0x10, 0x39, 0x21, 0xa6, 0xe7, 0x96, 0x59, 0x23, - 0xc6, 0xae, 0x1b, 0x76, 0xdb, 0xb5, 0xba, 0xde, 0x6b, 0xdd, 0x21, 0x6d, 0x83, 0x78, 0x7a, 0xff, - 0xd8, 0x15, 0x9f, 0xb2, 0xa6, 0x6e, 0xf3, 0xae, 0xfa, 0x07, 0x40, 0x7a, 0x97, 0x47, 0x8b, 0xee, - 0xc3, 0xd2, 0x80, 0x78, 0x7a, 0x51, 0xde, 0x92, 0xb7, 0x73, 0x3b, 0x37, 0x4a, 0xb3, 0x61, 0x97, - 0xf6, 0x88, 0xa7, 0x1b, 0xba, 0xa7, 0x57, 0x33, 0x81, 0xaf, 0x30, 0x34, 0x66, 0x4f, 0x54, 0x87, - 0x25, 0xef, 0xd4, 0x26, 0xc5, 0xc4, 0x96, 0xbc, 0xbd, 0xb2, 0x73, 0x2b, 0xce, 0x56, 0xb8, 0x09, - 0xdb, 0x67, 0xa7, 0x36, 0xe1, 0x34, 0xd4, 0x10, 0xb3, 0x27, 0x7a, 0x09, 0xd0, 0x19, 0x18, 0x6d, - 0xd7, 0xd3, 0xbd, 0xa1, 0x5b, 0xbc, 0xc4, 0x02, 0xb9, 0xbd, 0x80, 0xec, 0x29, 0x03, 0x62, 0xe2, - 0xda, 0x96, 0xe9, 0x92, 0xea, 0x4a, 0xe0, 0x2b, 0x11, 0x02, 0x4d, 0xc2, 0xd9, 0xce, 0x40, 0x80, - 0xd0, 0x73, 0xc8, 0x33, 0x96, 0x36, 0x4f, 0x5d, 0x71, 0x89, 0xb1, 0x2b, 0x71, 0xec, 0x4d, 0xfa, - 0xbe, 0xcb, 0x60, 0xd5, 0x42, 0xe0, 0x2b, 0x13, 0x86, 0x9a, 0x84, 0xf9, 0x52, 0x70, 0x00, 0x7a, - 0x03, 0x57, 0xa2, 0x9f, 0xdb, 0x8e, 0x88, 0xa6, 0x98, 0x64, 0x0e, 0x6e, 0x9d, 0xe1, 0x60, 0x14, - 0xfc, 0xf5, 0xc0, 0x57, 0xe2, 0x99, 0x34, 0x09, 0xaf, 0x99, 0xb3, 0x16, 0xd4, 0x33, 0xa3, 0xa4, - 0x78, 0x93, 0x74, 0xbc, 0xb6, 0x43, 0x3e, 0x1f, 0x12, 0xd7, 0x2b, 0xa6, 0xe6, 0x7b, 0xae, 0xd0, - 0xde, 0x2e, 0xc7, 0x63, 0x0e, 0xe7, 0x9e, 0x63, 0x99, 0xa8, 0x67, 0x7d, 0xd6, 0x02, 0x7d, 0x01, - 0x57, 0xa7, 0xf1, 0x62, 0xd2, 0x69, 0xe6, 0x7a, 0xfb, 0x6c, 0xd7, 0x62, 0xd6, 0x1b, 0x81, 0xaf, - 0xcc, 0xe1, 0xd2, 0x24, 0xbc, 0xae, 0xc7, 0xd8, 0x20, 0x0f, 0xd6, 0x47, 0x16, 0x3c, 0x4f, 0x7c, - 0xda, 0x19, 0xe6, 0xfb, 0x3f, 0x8b, 0x7c, 0xb3, 0xf4, 0xf1, 0x59, 0x17, 0x03, 0x5f, 0x89, 0xe5, - 0xd1, 0x24, 0x8c, 0xf4, 0x19, 0x3c, 0xdd, 0x3f, 0x51, 0x74, 0x31, 0x3b, 0x7f, 0xff, 0x44, 0xbc, - 0xf1, 0xfd, 0x13, 0x35, 0xa4, 0xfb, 0x27, 0x42, 0x8f, 0xba, 0x50, 0xa0, 0x47, 0xca, 0x3e, 0xd6, - 0x4d, 0x12, 0xee, 0xfc, 0x1c, 0xe3, 0xfe, 0x57, 0x1c, 0x77, 0x2d, 0xc4, 0xf2, 0x6d, 0x5d, 0x5d, - 0x0f, 0x7c, 0x65, 0x86, 0x40, 0x93, 0xf0, 0xaa, 0x31, 0x09, 0x44, 0x9f, 0x41, 0x9e, 0xe9, 0x43, - 0xdb, 0x21, 0xb6, 0xe5, 0x78, 0xc5, 0xfc, 0xfc, 0x6c, 0x71, 0x39, 0x29, 0xd5, 0x69, 0x83, 0x19, - 0x9a, 0x4f, 0x23, 0x6a, 0x4f, 0xa7, 0x41, 0xc6, 0x00, 0xf4, 0x8d, 0x0c, 0x1b, 0x91, 0x30, 0xa6, - 0x94, 0xa7, 0xb8, 0xcc, 0xbc, 0xdd, 0x59, 0x3c, 0x23, 0x61, 0x54, 0xe3, 0x36, 0xd5, 0xcd, 0xc0, - 0x57, 0x16, 0x70, 0x6a, 0x12, 0x2e, 0x1a, 0x73, 0x6c, 0x27, 0xb3, 0x3a, 0xb4, 0x0d, 0xdd, 0x23, - 0xc5, 0x95, 0x73, 0x64, 0xf5, 0x80, 0x41, 0xa7, 0xb3, 0xca, 0x09, 0x26, 0xb2, 0xca, 0x81, 0xea, - 0x5d, 0xc8, 0x45, 0x04, 0x0d, 0x01, 0xa4, 0x9a, 0x2d, 0xbc, 0x57, 0x79, 0x52, 0x90, 0x50, 0x1e, - 0x32, 0xb5, 0xd6, 0x8b, 0xe6, 0x93, 0x56, 0xa5, 0x56, 0x90, 0xe9, 0x97, 0x83, 0x7d, 0xd6, 0x4f, - 0x54, 0x53, 0xb0, 0x44, 0x79, 0xd4, 0xef, 0x2e, 0xc1, 0x95, 0x58, 0x25, 0x43, 0x9f, 0x42, 0x4a, - 0x6c, 0x05, 0x99, 0x29, 0xea, 0xbd, 0x73, 0x8b, 0xe0, 0xe4, 0x68, 0x15, 0x02, 0x5f, 0x11, 0x54, - 0x58, 0xb4, 0xa8, 0x0f, 0x40, 0x1c, 0xc7, 0x72, 0xda, 0x1d, 0xcb, 0x08, 0x25, 0xfb, 0xfe, 0x07, - 0x3b, 0xa8, 0x53, 0x8a, 0x5d, 0xcb, 0x10, 0xb2, 0x3b, 0x66, 0xc4, 0x59, 0x12, 0x7e, 0x42, 0x37, - 0x21, 0x3d, 0x20, 0xae, 0xab, 0xf7, 0x08, 0x53, 0xf3, 0x6c, 0x35, 0x17, 0xf8, 0x4a, 0x38, 0x84, - 0xc3, 0x0e, 0x52, 0x20, 0xc9, 0x6c, 0x98, 0x28, 0x67, 0xab, 0xd9, 0xc0, 0x57, 0xf8, 0x00, 0xe6, - 0x8d, 0xfa, 0x00, 0x96, 0x27, 0x82, 0x41, 0xab, 0x90, 0xdb, 0xdd, 0xab, 0xb5, 0x0f, 0x9a, 0x8f, - 0x9b, 0xad, 0x17, 0xcd, 0x82, 0x44, 0xf3, 0x4b, 0x07, 0x5a, 0x8f, 0x0b, 0x32, 0x5a, 0x86, 0x2c, - 0xed, 0xd7, 0x31, 0x6e, 0xe1, 0x42, 0x42, 0x2d, 0x43, 0x61, 0x3a, 0x66, 0x0a, 0xaf, 0x63, 0x4c, - 0xe1, 0x12, 0xe5, 0xa2, 0xfd, 0x90, 0x4b, 0x56, 0x7f, 0x48, 0xc2, 0xea, 0xd4, 0x39, 0x43, 0xff, - 0x85, 0xac, 0x7b, 0xea, 0x7a, 0x64, 0xd0, 0xee, 0x1b, 0x6c, 0x51, 0xb2, 0xd5, 0xe5, 0xc0, 0x57, - 0xc6, 0x83, 0x38, 0xc3, 0xbb, 0x0d, 0x03, 0x3d, 0x82, 0x74, 0xb8, 0xef, 0x13, 0x5b, 0x97, 0xb6, - 0x73, 0x3b, 0x5b, 0x73, 0x2f, 0x81, 0x70, 0xaf, 0xb3, 0xbc, 0x08, 0x23, 0x1c, 0x76, 0xe8, 0x95, - 0x4c, 0x2b, 0x00, 0x71, 0x13, 0xc6, 0x5e, 0xc9, 0x9a, 0xe5, 0x7a, 0x0d, 0xb3, 0x6b, 0xf1, 0xbb, - 0x94, 0xa2, 0x31, 0x7b, 0xa2, 0x87, 0x90, 0x3e, 0x24, 0xfa, 0xb1, 0x77, 0xe8, 0x16, 0x93, 0x2c, - 0x88, 0xf9, 0x57, 0x9d, 0xc6, 0x70, 0x3c, 0x06, 0x61, 0x83, 0xc3, 0x0e, 0xfa, 0x7a, 0xf1, 0xc1, - 0x4e, 0x31, 0xee, 0xbf, 0xf5, 0x60, 0x2f, 0x38, 0xd6, 0x5f, 0xc5, 0x07, 0x13, 0x4e, 0x34, 0xcd, - 0x82, 0xf9, 0xdf, 0xb9, 0x82, 0x11, 0x93, 0x9e, 0x17, 0x4b, 0x98, 0x87, 0xd9, 0x58, 0x34, 0x91, - 0x98, 0x93, 0xf0, 0xfa, 0xd5, 0x3b, 0x5e, 0xff, 0xa4, 0xef, 0x9d, 0x86, 0xea, 0x9d, 0x61, 0x51, - 0xcc, 0xbf, 0x7e, 0x2b, 0x02, 0x2f, 0x8e, 0x68, 0xe4, 0xfa, 0x9d, 0x62, 0x12, 0x97, 0xef, 0x24, - 0x5e, 0xfd, 0x56, 0x86, 0xb5, 0x18, 0x1e, 0x64, 0xc3, 0xda, 0x44, 0xf9, 0x10, 0x11, 0x90, 0xdc, - 0xce, 0xcd, 0x33, 0xca, 0x10, 0x11, 0xcb, 0xb5, 0xc0, 0x57, 0xe2, 0x58, 0x34, 0x09, 0x5f, 0x36, - 0x67, 0xd0, 0x19, 0x48, 0x89, 0x98, 0x7e, 0x95, 0xe1, 0xf2, 0x0c, 0x1b, 0xfa, 0x04, 0x56, 0x3a, - 0x96, 0xe3, 0x90, 0x63, 0xdd, 0xeb, 0x5b, 0xe6, 0xf8, 0xe0, 0xa0, 0xc0, 0x57, 0xa6, 0xbe, 0xe0, - 0xe5, 0xc8, 0x7b, 0xc3, 0x40, 0xfb, 0x23, 0x01, 0xe4, 0xfa, 0x74, 0xe7, 0x5c, 0xf1, 0x97, 0x16, - 0xa8, 0xde, 0xf9, 0xa4, 0x48, 0xdd, 0x0e, 0xe7, 0x84, 0x72, 0x90, 0xde, 0xaf, 0x37, 0x6b, 0x8d, - 0xe6, 0xa3, 0x82, 0x84, 0x52, 0x90, 0x60, 0xd2, 0x92, 0x85, 0x64, 0x28, 0x2b, 0xbf, 0xcb, 0x70, - 0x6d, 0xce, 0xae, 0x1a, 0x17, 0x9b, 0x7c, 0x1b, 0x89, 0x45, 0x38, 0xf3, 0x04, 0x46, 0x8a, 0x4d, - 0x6e, 0x38, 0x2a, 0x36, 0x05, 0xef, 0x5b, 0xb8, 0xaa, 0xdb, 0x76, 0x9b, 0x16, 0xef, 0xb4, 0x54, - 0x7a, 0xad, 0x77, 0x43, 0x0f, 0x89, 0x05, 0x35, 0x9f, 0x6d, 0xef, 0x73, 0x83, 0x17, 0x95, 0x87, - 0xc2, 0x13, 0xaf, 0xbb, 0x62, 0xa9, 0x58, 0xd1, 0x37, 0x36, 0xd1, 0xbb, 0xc2, 0x24, 0x03, 0x29, - 0x0e, 0x50, 0x7f, 0x96, 0x23, 0xfa, 0xc8, 0x2f, 0xc2, 0x91, 0x54, 0xc9, 0x7f, 0x41, 0xaa, 0xce, - 0x90, 0x98, 0xc4, 0x3f, 0x29, 0x31, 0xea, 0x1e, 0xac, 0xd6, 0xac, 0xd7, 0xe6, 0xb1, 0xa5, 0x1b, - 0x61, 0xe9, 0x77, 0x81, 0x5f, 0x46, 0xea, 0x97, 0x09, 0x58, 0x8b, 0x29, 0xf7, 0xd1, 0xde, 0xc4, - 0x0d, 0xff, 0x41, 0x3f, 0x73, 0xe2, 0x76, 0x77, 0x03, 0x52, 0x54, 0x3c, 0x2c, 0x53, 0x9c, 0x97, - 0xb3, 0xce, 0x7b, 0x85, 0x81, 0x39, 0x15, 0x37, 0xc4, 0xa2, 0x45, 0xcf, 0x21, 0x27, 0xce, 0x3e, - 0x9d, 0x90, 0xb8, 0x7b, 0xfe, 0x1d, 0x1f, 0x1e, 0x85, 0xd5, 0x88, 0xdb, 0x71, 0xfa, 0xb6, 0x67, - 0x39, 0xd5, 0xd5, 0xc0, 0x57, 0xa2, 0xc6, 0x18, 0xf8, 0x0b, 0x5d, 0x26, 0xf5, 0x37, 0x19, 0xf2, - 0x07, 0x36, 0xcd, 0xab, 0x38, 0x60, 0x17, 0xf9, 0xc1, 0xf9, 0x74, 0x4a, 0x1f, 0xca, 0x71, 0xd6, - 0x51, 0x6f, 0xa5, 0x67, 0x8e, 0x6e, 0xba, 0x5d, 0xe2, 0x2c, 0x90, 0x08, 0x15, 0x52, 0x0e, 0xd1, - 0x5d, 0xcb, 0x14, 0x0a, 0xc1, 0x30, 0x7c, 0x04, 0x8b, 0x56, 0xfd, 0x08, 0x56, 0x26, 0x99, 0xa8, - 0x4e, 0x8c, 0xcb, 0x90, 0x50, 0x27, 0x00, 0x52, 0x0f, 0x2b, 0x8d, 0x27, 0xf5, 0x5a, 0x21, 0xa1, - 0xfe, 0x28, 0x43, 0x96, 0x66, 0x60, 0xf7, 0x70, 0x68, 0x1e, 0xa1, 0x16, 0x3b, 0x46, 0x06, 0x71, - 0x16, 0x2e, 0x3c, 0x85, 0x12, 0x03, 0x13, 0xd7, 0x1a, 0x3a, 0x1d, 0xaa, 0x2a, 0x06, 0x71, 0x78, - 0x3c, 0xdc, 0x58, 0x93, 0xb0, 0xe8, 0x21, 0x8d, 0x57, 0x93, 0x42, 0x01, 0xb6, 0xcf, 0x41, 0xc7, - 0x5e, 0x79, 0x4a, 0xa9, 0xa5, 0x26, 0x61, 0xd6, 0x56, 0xd3, 0x90, 0xec, 0xd0, 0x4f, 0xea, 0x3b, - 0x19, 0xae, 0xc4, 0x86, 0x70, 0xa1, 0x35, 0x53, 0x21, 0xc5, 0xe8, 0xf9, 0x9a, 0x25, 0xf9, 0x74, - 0xf8, 0x08, 0x16, 0x2d, 0xda, 0x86, 0x4c, 0xe7, 0x90, 0x74, 0x8e, 0xdc, 0xe1, 0x40, 0x2c, 0x42, - 0x3e, 0xf0, 0x95, 0xd1, 0x18, 0x1e, 0xf5, 0xd0, 0xff, 0x01, 0x98, 0x4d, 0xdb, 0xed, 0xbf, 0x25, - 0xac, 0x70, 0x4c, 0x8a, 0x3f, 0x00, 0x46, 0xa3, 0x38, 0xcb, 0xfa, 0x4f, 0xfb, 0x6f, 0x89, 0xfa, - 0xbd, 0x0c, 0xeb, 0x71, 0x69, 0xb8, 0xd0, 0x8c, 0x6e, 0xd1, 0x68, 0xa9, 0xb7, 0xbe, 0x21, 0xe6, - 0x24, 0xa2, 0xe5, 0x63, 0x38, 0xcd, 0x7a, 0x0d, 0x03, 0xdd, 0x10, 0x6b, 0x44, 0xa7, 0x94, 0x1f, - 0x67, 0x5e, 0xe4, 0xfd, 0xde, 0x4f, 0xef, 0x37, 0xe5, 0x77, 0xef, 0x37, 0xe5, 0x5f, 0xde, 0x6f, - 0xca, 0x2f, 0x6f, 0xf7, 0xfa, 0xde, 0xe1, 0xf0, 0x55, 0xa9, 0x63, 0x0d, 0xca, 0x2c, 0x92, 0x32, - 0x8b, 0xa4, 0xec, 0x1a, 0x47, 0xe5, 0x93, 0x9d, 0x32, 0xfb, 0xe3, 0xe6, 0x01, 0x7b, 0xbe, 0x4a, - 0xb1, 0xe6, 0xee, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc3, 0xee, 0xd6, 0x35, 0x72, 0x12, 0x00, - 0x00, + // 1535 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcb, 0x6e, 0xdb, 0x46, + 0x17, 0x26, 0x15, 0xeb, 0x76, 0x24, 0xdb, 0xca, 0xd8, 0x49, 0x14, 0x23, 0x30, 0x0d, 0xfe, 0x7f, + 0x6a, 0xa7, 0x4d, 0x25, 0xd4, 0x41, 0x11, 0x34, 0x59, 0x59, 0x96, 0x13, 0x0a, 0x89, 0x65, 0x63, + 0x12, 0x27, 0x40, 0x8a, 0x42, 0x60, 0xc4, 0x91, 0x4c, 0xd8, 0x22, 0x59, 0x92, 0x72, 0xe2, 0xa0, + 0xfb, 0xa2, 0x45, 0x37, 0x5d, 0x74, 0xd1, 0xf6, 0x21, 0xfa, 0x1a, 0x5d, 0x66, 0xdd, 0x05, 0x51, + 0x64, 0xc9, 0x07, 0x68, 0x17, 0xdd, 0x14, 0x73, 0xa1, 0x44, 0x49, 0x94, 0xec, 0xd4, 0x45, 0x37, + 0x9a, 0xe1, 0xf0, 0x3b, 0xdf, 0xb9, 0xcc, 0xcc, 0x37, 0x43, 0xc1, 0x7c, 0xdb, 0xee, 0xf5, 0x74, + 0xcb, 0xa8, 0x38, 0xae, 0xed, 0xdb, 0x08, 0x75, 0x3e, 0xad, 0x58, 0x5d, 0xd3, 0x7a, 0x5d, 0xd1, + 0xbb, 0xc4, 0xf2, 0x2b, 0x9e, 0x71, 0xb4, 0x02, 0x5d, 0xbb, 0x6b, 0xf3, 0xf7, 0x2b, 0x45, 0x0a, + 0xb7, 0x2d, 0xf1, 0x54, 0xe0, 0x20, 0xfe, 0x00, 0x87, 0xb6, 0x17, 0xf5, 0x0b, 0x9c, 0x63, 0x60, + 0x63, 0x75, 0xcc, 0xae, 0x78, 0x42, 0xe4, 0x84, 0x58, 0xbe, 0x57, 0x65, 0x8d, 0x18, 0xbb, 0x6e, + 0x38, 0x2d, 0xcf, 0xee, 0xf8, 0xaf, 0x74, 0x97, 0xb4, 0x0c, 0xe2, 0xeb, 0xe6, 0xb1, 0x27, 0x5e, + 0xe5, 0x2d, 0xdd, 0xe1, 0x5d, 0xf5, 0x2f, 0x80, 0xec, 0x36, 0x8f, 0x16, 0xdd, 0x83, 0xb9, 0x1e, + 0xf1, 0xf5, 0xb2, 0xbc, 0x26, 0x6f, 0x14, 0x36, 0x6f, 0x54, 0x26, 0xc3, 0xae, 0xec, 0x12, 0x5f, + 0x37, 0x74, 0x5f, 0xaf, 0xe5, 0xc2, 0x40, 0x61, 0x68, 0xcc, 0x7e, 0xd1, 0x0e, 0xcc, 0xf9, 0xa7, + 0x0e, 0x29, 0xa7, 0xd6, 0xe4, 0x8d, 0x85, 0xcd, 0xf5, 0x24, 0x5b, 0xe1, 0x26, 0x6a, 0x9f, 0x9e, + 0x3a, 0x84, 0xd3, 0x50, 0x43, 0xcc, 0x7e, 0xd1, 0x0b, 0x80, 0x76, 0xcf, 0x68, 0x79, 0xbe, 0xee, + 0xf7, 0xbd, 0xf2, 0x25, 0x16, 0xc8, 0xad, 0x19, 0x64, 0x4f, 0x18, 0x10, 0x13, 0xcf, 0xb1, 0x2d, + 0x8f, 0xd4, 0x16, 0xc2, 0x40, 0x89, 0x11, 0x68, 0x12, 0xce, 0xb7, 0x7b, 0x02, 0x84, 0x9e, 0x41, + 0x91, 0xb1, 0xb4, 0x78, 0xe9, 0xca, 0x73, 0x8c, 0x5d, 0x49, 0x62, 0x6f, 0xd2, 0xe7, 0x6d, 0x06, + 0xab, 0x95, 0xc2, 0x40, 0x19, 0x31, 0xd4, 0x24, 0xcc, 0xa7, 0x82, 0x03, 0xd0, 0x6b, 0xb8, 0x12, + 0x7f, 0xdd, 0x72, 0x45, 0x34, 0xe5, 0x34, 0x73, 0xb0, 0x7e, 0x86, 0x83, 0x41, 0xf0, 0xd7, 0xc3, + 0x40, 0x49, 0x66, 0xd2, 0x24, 0xbc, 0x64, 0x4d, 0x5a, 0x50, 0xcf, 0x8c, 0x92, 0xe2, 0x2d, 0xd2, + 0xf6, 0x5b, 0x2e, 0xf9, 0xb2, 0x4f, 0x3c, 0xbf, 0x9c, 0x99, 0xee, 0x79, 0x8b, 0xf6, 0xb6, 0x39, + 0x1e, 0x73, 0x38, 0xf7, 0x9c, 0xc8, 0x44, 0x3d, 0xeb, 0x93, 0x16, 0xe8, 0x2b, 0xb8, 0x3a, 0x8e, + 0x17, 0x49, 0x67, 0x99, 0xeb, 0x8d, 0xb3, 0x5d, 0x8b, 0xac, 0x57, 0xc2, 0x40, 0x99, 0xc2, 0xa5, + 0x49, 0x78, 0x59, 0x4f, 0xb0, 0x41, 0x3e, 0x2c, 0x0f, 0x2c, 0x78, 0x9d, 0x78, 0xda, 0x39, 0xe6, + 0xfb, 0x83, 0x59, 0xbe, 0x59, 0xf9, 0x78, 0xd6, 0xe5, 0x30, 0x50, 0x12, 0x79, 0x34, 0x09, 0x23, + 0x7d, 0x02, 0x4f, 0xd7, 0x4f, 0x1c, 0x5d, 0xce, 0x4f, 0x5f, 0x3f, 0x31, 0x6f, 0x7c, 0xfd, 0xc4, + 0x0d, 0xe9, 0xfa, 0x89, 0xd1, 0xa3, 0x0e, 0x94, 0xe8, 0x96, 0x72, 0x8e, 0x75, 0x8b, 0x44, 0x2b, + 0xbf, 0xc0, 0xb8, 0xff, 0x97, 0xc4, 0x5d, 0x8f, 0xb0, 0x7c, 0x59, 0xd7, 0x96, 0xc3, 0x40, 0x99, + 0x20, 0xd0, 0x24, 0xbc, 0x68, 0x8c, 0x02, 0xd1, 0x17, 0x50, 0x64, 0xfa, 0xd0, 0x72, 0x89, 0x63, + 0xbb, 0x7e, 0xb9, 0x38, 0xbd, 0x5a, 0x5c, 0x4e, 0x2a, 0x3b, 0xb4, 0xc1, 0x0c, 0xcd, 0xd3, 0x88, + 0xdb, 0xd3, 0x34, 0xc8, 0x10, 0x80, 0xbe, 0x93, 0x61, 0x25, 0x16, 0xc6, 0x98, 0xf2, 0x94, 0xe7, + 0x99, 0xb7, 0xdb, 0xb3, 0x33, 0x12, 0x46, 0x75, 0x6e, 0x53, 0x5b, 0x0d, 0x03, 0x65, 0x06, 0xa7, + 0x26, 0xe1, 0xb2, 0x31, 0xc5, 0x76, 0xb4, 0xaa, 0x7d, 0xc7, 0xd0, 0x7d, 0x52, 0x5e, 0x38, 0x47, + 0x55, 0x0f, 0x18, 0x74, 0xbc, 0xaa, 0x9c, 0x60, 0xa4, 0xaa, 0x1c, 0xa8, 0xde, 0x81, 0x42, 0x4c, + 0xd0, 0x10, 0x40, 0xa6, 0xb9, 0x87, 0x77, 0xb7, 0x1e, 0x97, 0x24, 0x54, 0x84, 0x5c, 0x7d, 0xef, + 0x79, 0xf3, 0xf1, 0xde, 0x56, 0xbd, 0x24, 0xd3, 0x37, 0x07, 0xfb, 0xac, 0x9f, 0xaa, 0x65, 0x60, + 0x8e, 0xf2, 0xa8, 0x3f, 0x5c, 0x82, 0x2b, 0x89, 0x4a, 0x86, 0x3e, 0x87, 0x8c, 0x58, 0x0a, 0x32, + 0x53, 0xd4, 0xbb, 0xe7, 0x16, 0xc1, 0xd1, 0xd1, 0x1a, 0x84, 0x81, 0x22, 0xa8, 0xb0, 0x68, 0x91, + 0x09, 0x40, 0x5c, 0xd7, 0x76, 0x5b, 0x6d, 0xdb, 0x88, 0x24, 0xfb, 0xde, 0x7b, 0x3b, 0xd8, 0xa1, + 0x14, 0xdb, 0xb6, 0x21, 0x64, 0x77, 0xc8, 0x88, 0xf3, 0x24, 0x7a, 0x85, 0x6e, 0x42, 0xb6, 0x47, + 0x3c, 0x4f, 0xef, 0x12, 0xa6, 0xe6, 0xf9, 0x5a, 0x21, 0x0c, 0x94, 0x68, 0x08, 0x47, 0x1d, 0xa4, + 0x40, 0x9a, 0xd9, 0x30, 0x51, 0xce, 0xd7, 0xf2, 0x61, 0xa0, 0xf0, 0x01, 0xcc, 0x1b, 0xf5, 0x3e, + 0xcc, 0x8f, 0x04, 0x83, 0x16, 0xa1, 0xb0, 0xbd, 0x5b, 0x6f, 0x1d, 0x34, 0x1f, 0x35, 0xf7, 0x9e, + 0x37, 0x4b, 0x12, 0xad, 0x2f, 0x1d, 0xd8, 0x7b, 0x54, 0x92, 0xd1, 0x3c, 0xe4, 0x69, 0x7f, 0x07, + 0xe3, 0x3d, 0x5c, 0x4a, 0xa9, 0x55, 0x28, 0x8d, 0xc7, 0x4c, 0xe1, 0x3b, 0x18, 0x53, 0xb8, 0x44, + 0xb9, 0x68, 0x3f, 0xe2, 0x92, 0xd5, 0x9f, 0xd3, 0xb0, 0x38, 0xb6, 0xcf, 0xd0, 0x87, 0x90, 0xf7, + 0x4e, 0x3d, 0x9f, 0xf4, 0x5a, 0xa6, 0xc1, 0x26, 0x25, 0x5f, 0x9b, 0x0f, 0x03, 0x65, 0x38, 0x88, + 0x73, 0xbc, 0xdb, 0x30, 0xd0, 0x43, 0xc8, 0x46, 0xeb, 0x3e, 0xb5, 0x76, 0x69, 0xa3, 0xb0, 0xb9, + 0x36, 0xf5, 0x10, 0x88, 0xd6, 0x3a, 0xab, 0x8b, 0x30, 0xc2, 0x51, 0x87, 0x1e, 0xc9, 0xf4, 0x06, + 0x20, 0x4e, 0xc2, 0xc4, 0x23, 0x59, 0xb3, 0x3d, 0xbf, 0x61, 0x75, 0x6c, 0x7e, 0x96, 0x52, 0x34, + 0x66, 0xbf, 0xe8, 0x01, 0x64, 0x0f, 0x89, 0x7e, 0xec, 0x1f, 0x7a, 0xe5, 0x34, 0x0b, 0x62, 0xfa, + 0x51, 0xa7, 0x31, 0x1c, 0x8f, 0x41, 0xd8, 0xe0, 0xa8, 0x83, 0xbe, 0x9d, 0xbd, 0xb1, 0x33, 0x8c, + 0xfb, 0x5f, 0xdd, 0xd8, 0x33, 0xb6, 0xf5, 0x37, 0xc9, 0xc1, 0x44, 0x89, 0x66, 0x59, 0x30, 0x1f, + 0x9d, 0x2b, 0x18, 0x91, 0xf4, 0xb4, 0x58, 0xa2, 0x3a, 0x4c, 0xc6, 0xa2, 0x89, 0xc2, 0x9c, 0x44, + 0xc7, 0xaf, 0xde, 0xf6, 0xcd, 0x13, 0xd3, 0x3f, 0x8d, 0xd4, 0x3b, 0xc7, 0xa2, 0x98, 0x7e, 0xfc, + 0x6e, 0x09, 0xbc, 0xd8, 0xa2, 0xb1, 0xe3, 0x77, 0x8c, 0x49, 0x1c, 0xbe, 0xa3, 0x78, 0xf5, 0x7b, + 0x19, 0x96, 0x12, 0x78, 0x90, 0x03, 0x4b, 0x23, 0xd7, 0x87, 0x98, 0x80, 0x14, 0x36, 0x6f, 0x9e, + 0x71, 0x0d, 0x11, 0xb1, 0x5c, 0x0b, 0x03, 0x25, 0x89, 0x45, 0x93, 0xf0, 0x65, 0x6b, 0x02, 0x9d, + 0x83, 0x8c, 0x88, 0xe9, 0xa7, 0x14, 0x5c, 0x9e, 0x60, 0x43, 0x9f, 0xc1, 0x42, 0xdb, 0x76, 0x5d, + 0x72, 0xac, 0xfb, 0xa6, 0x6d, 0x0d, 0x37, 0x0e, 0x0a, 0x03, 0x65, 0xec, 0x0d, 0x9e, 0x8f, 0x3d, + 0x37, 0x0c, 0xb4, 0x3f, 0x10, 0x40, 0xae, 0x4f, 0xb7, 0xcf, 0x15, 0x7f, 0x65, 0x86, 0xea, 0x9d, + 0x53, 0x8a, 0xd6, 0x21, 0xc7, 0xf3, 0x37, 0x0d, 0xa1, 0x46, 0xc5, 0x30, 0x50, 0x06, 0x63, 0x38, + 0xcb, 0x7a, 0x0d, 0x43, 0xdd, 0x88, 0x92, 0x47, 0x05, 0xc8, 0xee, 0xef, 0x34, 0xeb, 0x8d, 0xe6, + 0xc3, 0x92, 0x84, 0x32, 0x90, 0x62, 0x1a, 0x94, 0x87, 0x74, 0xa4, 0x3f, 0x7f, 0xca, 0x70, 0x6d, + 0xca, 0xf2, 0x1b, 0xde, 0x4a, 0xf9, 0x7a, 0x13, 0xb3, 0x75, 0xe6, 0x56, 0x8d, 0xdd, 0x4a, 0xb9, + 0xe1, 0xe0, 0x56, 0x2a, 0x78, 0xdf, 0xc0, 0x55, 0xdd, 0x71, 0x5a, 0xf4, 0x96, 0x4f, 0xef, 0x54, + 0xaf, 0xf4, 0x4e, 0xe4, 0x21, 0x35, 0xe3, 0x72, 0xe8, 0x38, 0xfb, 0xdc, 0xe0, 0xf9, 0xd6, 0x03, + 0xe1, 0x89, 0x5f, 0xd0, 0x12, 0xa9, 0xd8, 0xed, 0x70, 0x68, 0xa2, 0x77, 0x84, 0x49, 0x0e, 0x32, + 0x1c, 0xa0, 0xfe, 0x26, 0xc7, 0x84, 0x94, 0x9f, 0x98, 0x03, 0x4d, 0x93, 0xff, 0x81, 0xa6, 0x9d, + 0xa1, 0x45, 0xa9, 0xff, 0x52, 0x8b, 0xd4, 0x5d, 0x58, 0xac, 0xdb, 0xaf, 0xac, 0x63, 0x5b, 0x37, + 0xa2, 0x3b, 0xe2, 0x05, 0x3e, 0xa1, 0xd4, 0xaf, 0x53, 0xb0, 0x94, 0xf0, 0x5d, 0x80, 0x76, 0x47, + 0xae, 0x02, 0xef, 0xf5, 0x3d, 0x94, 0xb4, 0x0d, 0x1a, 0x90, 0xa1, 0x2a, 0x63, 0x5b, 0x62, 0x63, + 0x9d, 0x25, 0x0c, 0x5b, 0x0c, 0xcc, 0xa9, 0xb8, 0x21, 0x16, 0x2d, 0x7a, 0x06, 0x05, 0x21, 0x12, + 0x34, 0x21, 0x71, 0x48, 0xfd, 0x3f, 0x39, 0x3c, 0x0a, 0xab, 0x13, 0xaf, 0xed, 0x9a, 0x8e, 0x6f, + 0xbb, 0xb5, 0xc5, 0x30, 0x50, 0xe2, 0xc6, 0x18, 0xf8, 0x03, 0x9d, 0x26, 0xf5, 0x0f, 0x19, 0x8a, + 0x07, 0x0e, 0xad, 0xab, 0xd8, 0x60, 0x17, 0xf9, 0x32, 0x7d, 0x32, 0x26, 0x24, 0xd5, 0x24, 0xeb, + 0xb8, 0xb7, 0xca, 0x53, 0x57, 0xb7, 0xbc, 0x0e, 0x71, 0x67, 0x68, 0x89, 0x0a, 0x19, 0x97, 0xe8, + 0x9e, 0x6d, 0x09, 0x29, 0x61, 0x18, 0x3e, 0x82, 0x45, 0xab, 0x7e, 0x02, 0x0b, 0xa3, 0x4c, 0x54, + 0x27, 0x86, 0xf7, 0x95, 0x48, 0x27, 0x00, 0x32, 0x0f, 0xb6, 0x1a, 0x8f, 0x77, 0xea, 0xa5, 0x94, + 0xfa, 0x8b, 0x0c, 0x79, 0x5a, 0x81, 0xed, 0xc3, 0xbe, 0x75, 0x84, 0xf6, 0xd8, 0x36, 0x32, 0x88, + 0x3b, 0x73, 0xe2, 0x29, 0x94, 0x18, 0x98, 0x78, 0x76, 0xdf, 0x6d, 0x53, 0x55, 0x31, 0x88, 0xcb, + 0xe3, 0xe1, 0xc6, 0x9a, 0x84, 0x45, 0x0f, 0x69, 0xfc, 0xda, 0x29, 0x14, 0x60, 0xe3, 0x1c, 0x74, + 0xec, 0x91, 0x97, 0x94, 0x5a, 0x6a, 0x12, 0x66, 0x6d, 0x2d, 0x0b, 0xe9, 0x36, 0x7d, 0xa5, 0xbe, + 0x95, 0xe1, 0x4a, 0x62, 0x08, 0x17, 0x9a, 0x33, 0x15, 0x32, 0x8c, 0x9e, 0xcf, 0x59, 0x9a, 0xa7, + 0xc3, 0x47, 0xb0, 0x68, 0xd1, 0x06, 0xe4, 0xda, 0x87, 0xa4, 0x7d, 0xe4, 0xf5, 0x7b, 0x62, 0x12, + 0x98, 0x4e, 0x47, 0x63, 0x78, 0xd0, 0x43, 0x1f, 0x03, 0x30, 0x9b, 0x96, 0x67, 0xbe, 0x21, 0x4c, + 0xd3, 0xd3, 0xe2, 0x9f, 0x82, 0xc1, 0x28, 0xce, 0xb3, 0xfe, 0x13, 0xf3, 0x0d, 0x51, 0x7f, 0x94, + 0x61, 0x39, 0xa9, 0x0c, 0x17, 0xca, 0x68, 0x9d, 0x46, 0x4b, 0xbd, 0x99, 0x86, 0xc8, 0x49, 0x44, + 0xcb, 0xc7, 0x70, 0x96, 0xf5, 0x1a, 0x06, 0xba, 0x21, 0xe6, 0x88, 0xa6, 0x54, 0x1c, 0x56, 0x5e, + 0xd4, 0xfd, 0xee, 0xaf, 0xef, 0x56, 0xe5, 0xb7, 0xef, 0x56, 0xe5, 0xdf, 0xdf, 0xad, 0xca, 0x2f, + 0x6e, 0x75, 0x4d, 0xff, 0xb0, 0xff, 0xb2, 0xd2, 0xb6, 0x7b, 0x55, 0x16, 0x49, 0x95, 0x45, 0x52, + 0xf5, 0x8c, 0xa3, 0xea, 0xc9, 0x66, 0x95, 0xfd, 0xc3, 0x73, 0x9f, 0xfd, 0xbe, 0xcc, 0xb0, 0xe6, + 0xce, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x1f, 0x57, 0x17, 0x9b, 0x12, 0x00, 0x00, } func (m *Command) Marshal() (dAtA []byte, err error) { @@ -1884,6 +1892,13 @@ func (m *NginxConfigStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.NginxId) > 0 { + i -= len(m.NginxId) + copy(dAtA[i:], m.NginxId) + i = encodeVarintCommand(dAtA, i, uint64(len(m.NginxId))) + i-- + dAtA[i] = 0x22 + } if len(m.Message) > 0 { i -= len(m.Message) copy(dAtA[i:], m.Message) @@ -2653,6 +2668,10 @@ func (m *NginxConfigStatus) Size() (n int) { if l > 0 { n += 1 + l + sovCommand(uint64(l)) } + l = len(m.NginxId) + if l > 0 { + n += 1 + l + sovCommand(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -4007,6 +4026,38 @@ func (m *NginxConfigStatus) Unmarshal(dAtA []byte) error { } m.Message = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NginxId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommand + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommand + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommand + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NginxId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipCommand(dAtA[iNdEx:]) diff --git a/sdk/proto/command.proto b/sdk/proto/command.proto index 4ae215aa5..feb738c3c 100644 --- a/sdk/proto/command.proto +++ b/sdk/proto/command.proto @@ -103,6 +103,7 @@ message NginxConfigStatus { string correlation_id = 1 [(gogoproto.jsontag) = "correlation_id" ]; Status status = 2 [(gogoproto.jsontag) = "status" ]; string message = 3 [(gogoproto.jsontag) = "message" ]; + string nginx_id = 4 [(gogoproto.jsontag) = "nginx_id" ]; enum Status { PENDING = 0; diff --git a/sdk/proto/events/event.pb.go b/sdk/proto/events/event.pb.go index 0d8ac2fec..903408281 100644 --- a/sdk/proto/events/event.pb.go +++ b/sdk/proto/events/event.pb.go @@ -123,6 +123,7 @@ func (m *Metadata) GetCategory() string { type Event struct { Metadata *Metadata `protobuf:"bytes,1,opt,name=Metadata,proto3" json:"metadata"` // Types that are valid to be assigned to Data: + // // *Event_ActivityEvent // *Event_SecurityViolationEvent Data isEvent_Data `protobuf_oneof:"data"` diff --git a/src/plugins/agent_api.go b/src/plugins/agent_api.go index 048b1be87..fe6346543 100644 --- a/src/plugins/agent_api.go +++ b/src/plugins/agent_api.go @@ -53,12 +53,12 @@ type AgentAPI struct { } type NginxHandler struct { - config *config.Config - env core.Environment - pipeline core.MessagePipeInterface - nginxBinary core.NginxBinary - responseChannel chan *proto.Command_NginxConfigResponse - configResponseStatus *proto.NginxConfigStatus + config *config.Config + env core.Environment + pipeline core.MessagePipeInterface + nginxBinary core.NginxBinary + responseChannel chan *proto.Command_NginxConfigResponse + configResponseStatuses map[string]*proto.NginxConfigStatus } type AgentAPIConfigApplyRequest struct { @@ -136,7 +136,9 @@ func (a *AgentAPI) Process(message *core.Message) { case core.NginxConfigValidationPending, core.NginxConfigApplyFailed, core.NginxConfigApplySucceeded: switch response := message.Data().(type) { case *proto.AgentActivityStatus: - a.nginxHandler.configResponseStatus = response.GetNginxConfigStatus() + log.Error(response) + nginxConfigStatus := response.GetNginxConfigStatus() + a.nginxHandler.configResponseStatuses[nginxConfigStatus.GetNginxId()] = nginxConfigStatus default: log.Errorf("Expected the type %T but got %T", &proto.AgentActivityStatus{}, response) } @@ -158,12 +160,12 @@ func (a *AgentAPI) Subscriptions() []string { func (a *AgentAPI) createHttpServer() { a.nginxHandler = &NginxHandler{ - config: a.config, - pipeline: a.pipeline, - env: a.env, - nginxBinary: a.nginxBinary, - responseChannel: make(chan *proto.Command_NginxConfigResponse), - configResponseStatus: &proto.NginxConfigStatus{}, + config: a.config, + pipeline: a.pipeline, + env: a.env, + nginxBinary: a.nginxBinary, + responseChannel: make(chan *proto.Command_NginxConfigResponse), + configResponseStatuses: make(map[string]*proto.NginxConfigStatus), } mux := http.NewServeMux() @@ -424,7 +426,23 @@ func (h *NginxHandler) getConfigStatus(w http.ResponseWriter, r *http.Request) e return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) } - if h.configResponseStatus.GetCorrelationId() != correlationId { + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyResponse{ + CorrelationId: correlationId, + NginxInstances: []NginxInstanceResponse{}, + } + + for _, nginxConfigStatus := range h.configResponseStatuses { + if nginxConfigStatus.GetCorrelationId() == correlationId { + nginxInstanceResponse := NginxInstanceResponse{ + NginxId: nginxConfigStatus.GetNginxId(), + Message: nginxConfigStatus.GetMessage(), + Status: nginxConfigStatus.GetStatus().String(), + } + agentAPIConfigApplyStatusResponse.NginxInstances = append(agentAPIConfigApplyStatusResponse.NginxInstances, nginxInstanceResponse) + } + } + + if len(agentAPIConfigApplyStatusResponse.NginxInstances) == 0 { w.WriteHeader(http.StatusNotFound) agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ CorrelationId: correlationId, @@ -436,13 +454,6 @@ func (h *NginxHandler) getConfigStatus(w http.ResponseWriter, r *http.Request) e } w.WriteHeader(http.StatusOK) - - agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ - CorrelationId: correlationId, - Message: h.configResponseStatus.Message, - Status: h.configResponseStatus.Status.String(), - } - return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) } diff --git a/src/plugins/agent_api_test.go b/src/plugins/agent_api_test.go index 87d97fbc3..877643120 100644 --- a/src/plugins/agent_api_test.go +++ b/src/plugins/agent_api_test.go @@ -324,36 +324,39 @@ func TestNginxHandler_updateConfig(t *testing.T) { func TestNginxHandler_getConfigStatus(t *testing.T) { tests := []struct { - name string - url string - configResponseStatus *proto.NginxConfigStatus - expectedStatusCode int - expectedMessage string - expectedStatus string + name string + url string + configResponseStatuses map[string]*proto.NginxConfigStatus + expectedStatusCode int + expectedMessage string + expectedStatus string }{ { - name: "no query parameter", - url: "/nginx/config/status/", - configResponseStatus: nil, - expectedStatusCode: 400, - expectedMessage: "Missing required query parameter correlation_id", - expectedStatus: "UNKNOWN", + name: "no query parameter", + url: "/nginx/config/status/", + configResponseStatuses: make(map[string]*proto.NginxConfigStatus), + expectedStatusCode: 400, + expectedMessage: "Missing required query parameter correlation_id", + expectedStatus: "UNKNOWN", }, { - name: "no matching correlation_id", - url: "/nginx/config/status/?correlation_id=123", - configResponseStatus: nil, - expectedStatusCode: 404, - expectedMessage: "Unable to find a config apply request with the correlation_id 123", - expectedStatus: "UNKNOWN", + name: "no matching correlation_id", + url: "/nginx/config/status/?correlation_id=123", + configResponseStatuses: make(map[string]*proto.NginxConfigStatus), + expectedStatusCode: 404, + expectedMessage: "Unable to find a config apply request with the correlation_id 123", + expectedStatus: "UNKNOWN", }, { name: "found matching correlation_id", url: "/nginx/config/status/?correlation_id=123", - configResponseStatus: &proto.NginxConfigStatus{ - CorrelationId: "123", - Status: proto.NginxConfigStatus_OK, - Message: "config applied successfully", + configResponseStatuses: map[string]*proto.NginxConfigStatus{ + "12345": { + CorrelationId: "123", + Status: proto.NginxConfigStatus_OK, + Message: "config applied successfully", + NginxId: "12345", + }, }, expectedStatusCode: 200, expectedMessage: "config applied successfully", @@ -365,12 +368,12 @@ func TestNginxHandler_getConfigStatus(t *testing.T) { w := httptest.NewRecorder() r := httptest.NewRequest(http.MethodGet, tt.url, nil) h := &NginxHandler{ - config: config.Defaults, - env: tutils.GetMockEnv(), - pipeline: core.NewMessagePipe(context.TODO()), - nginxBinary: tutils.NewMockNginxBinary(), - responseChannel: make(chan *proto.Command_NginxConfigResponse), - configResponseStatus: tt.configResponseStatus, + config: config.Defaults, + env: tutils.GetMockEnv(), + pipeline: core.NewMessagePipe(context.TODO()), + nginxBinary: tutils.NewMockNginxBinary(), + responseChannel: make(chan *proto.Command_NginxConfigResponse), + configResponseStatuses: tt.configResponseStatuses, } err := h.getConfigStatus(w, r) @@ -381,11 +384,21 @@ func TestNginxHandler_getConfigStatus(t *testing.T) { resp := w.Result() defer resp.Body.Close() - result := &AgentAPIConfigApplyStatusResponse{} - err = json.NewDecoder(w.Body).Decode(result) - assert.NoError(t, err) - assert.Equal(t, tt.expectedMessage, result.Message) - assert.Equal(t, tt.expectedStatus, result.Status) + if len(tt.configResponseStatuses) > 0 { + result := &AgentAPIConfigApplyResponse{} + err = json.NewDecoder(w.Body).Decode(result) + assert.NoError(t, err) + assert.Equal(t, tt.expectedMessage, result.NginxInstances[0].Message) + assert.Equal(t, tt.expectedStatus, result.NginxInstances[0].Status) + assert.Equal(t, "12345", result.NginxInstances[0].NginxId) + + } else { + result := &AgentAPIConfigApplyStatusResponse{} + err = json.NewDecoder(w.Body).Decode(result) + assert.NoError(t, err) + assert.Equal(t, tt.expectedMessage, result.Message) + assert.Equal(t, tt.expectedStatus, result.Status) + } }) } } diff --git a/src/plugins/dataplane_status.go b/src/plugins/dataplane_status.go index 255ff91c8..dc6a433f2 100644 --- a/src/plugins/dataplane_status.go +++ b/src/plugins/dataplane_status.go @@ -23,25 +23,25 @@ import ( ) type DataPlaneStatus struct { - messagePipeline core.MessagePipeInterface - ctx context.Context - sendStatus chan bool - healthTicker *time.Ticker - interval time.Duration - meta *proto.Metadata - binary core.NginxBinary - env core.Environment - version string - tags *[]string - configDirs string - lastSendDetails time.Time - envHostInfo *proto.HostInfo - statusUrls map[string]string - reportInterval time.Duration - napDetails *proto.DataplaneSoftwareDetails_AppProtectWafDetails - agentActivityStatuses []*proto.AgentActivityStatus - napDetailsMutex sync.RWMutex - napHealth *proto.DataplaneSoftwareHealth_AppProtectWafHealth + messagePipeline core.MessagePipeInterface + ctx context.Context + sendStatus chan bool + healthTicker *time.Ticker + interval time.Duration + meta *proto.Metadata + binary core.NginxBinary + env core.Environment + version string + tags *[]string + configDirs string + lastSendDetails time.Time + envHostInfo *proto.HostInfo + statusUrls map[string]string + reportInterval time.Duration + napDetails *proto.DataplaneSoftwareDetails_AppProtectWafDetails + nginxConfigActivityStatuses map[string]*proto.AgentActivityStatus + napDetailsMutex sync.RWMutex + napHealth *proto.DataplaneSoftwareHealth_AppProtectWafHealth } const ( @@ -56,18 +56,19 @@ func NewDataPlaneStatus(config *config.Config, meta *proto.Metadata, binary core log.Warnf("interval set to %s, provided value (%s) less than minimum", pollInt, config.Dataplane.Status.PollInterval) } return &DataPlaneStatus{ - sendStatus: make(chan bool), - healthTicker: time.NewTicker(pollInt), - interval: pollInt, - meta: meta, - binary: binary, - env: env, - version: version, - tags: &config.Tags, - configDirs: config.ConfigDirs, - statusUrls: make(map[string]string), - reportInterval: config.Dataplane.Status.ReportInterval, - napDetailsMutex: sync.RWMutex{}, + sendStatus: make(chan bool), + healthTicker: time.NewTicker(pollInt), + interval: pollInt, + meta: meta, + binary: binary, + env: env, + version: version, + tags: &config.Tags, + configDirs: config.ConfigDirs, + statusUrls: make(map[string]string), + reportInterval: config.Dataplane.Status.ReportInterval, + napDetailsMutex: sync.RWMutex{}, + nginxConfigActivityStatuses: make(map[string]*proto.AgentActivityStatus), // Intentionally empty as it will be set later napDetails: nil, napHealth: &proto.DataplaneSoftwareHealth_AppProtectWafHealth{}, @@ -112,7 +113,7 @@ func (dps *DataPlaneStatus) Process(msg *core.Message) { log.Tracef("DataplaneStatus: %T message from topic %s received", msg.Data(), msg.Topic()) switch data := msg.Data().(type) { case *proto.AgentActivityStatus: - dps.updateAgentActivityStatuses(data) + dps.updateNginxConfigActivityStatuses(data) default: log.Errorf("Expected the type %T but got %T", &proto.AgentActivityStatus{}, data) } @@ -121,9 +122,8 @@ func (dps *DataPlaneStatus) Process(msg *core.Message) { log.Tracef("DataplaneStatus: %T message from topic %s received", msg.Data(), msg.Topic()) switch data := msg.Data().(type) { case *proto.AgentActivityStatus: - dps.updateAgentActivityStatuses(data) + dps.updateNginxConfigActivityStatuses(data) dps.sendDataplaneStatus(dps.messagePipeline, false) - dps.removeAgentActivityStatus(data) default: log.Errorf("Expected the type %T but got %T", &proto.AgentActivityStatus{}, data) } @@ -140,34 +140,10 @@ func (dps *DataPlaneStatus) Subscriptions() []string { } } -func (dps *DataPlaneStatus) updateAgentActivityStatuses(newAgentActivityStatus *proto.AgentActivityStatus) { - log.Tracef("DataplaneStatus: Adding %v to agentActivityStatuses", newAgentActivityStatus) +func (dps *DataPlaneStatus) updateNginxConfigActivityStatuses(newAgentActivityStatus *proto.AgentActivityStatus) { + log.Tracef("DataplaneStatus: Updating nginxConfigActivityStatuses with %v", newAgentActivityStatus) if _, ok := newAgentActivityStatus.GetStatus().(*proto.AgentActivityStatus_NginxConfigStatus); ok { - foundExistingNginxStatus := false - for index, agentActivityStatus := range dps.agentActivityStatuses { - if _, ok := agentActivityStatus.GetStatus().(*proto.AgentActivityStatus_NginxConfigStatus); ok { - dps.agentActivityStatuses[index] = newAgentActivityStatus - log.Tracef("DataplaneStatus: Updated agentActivityStatus with new status %v", newAgentActivityStatus) - foundExistingNginxStatus = true - } - } - - if !foundExistingNginxStatus { - dps.agentActivityStatuses = append(dps.agentActivityStatuses, newAgentActivityStatus) - log.Tracef("DataplaneStatus: Added new status %v to agentActivityStatus", newAgentActivityStatus) - } - } -} - -func (dps *DataPlaneStatus) removeAgentActivityStatus(agentActivityStatus *proto.AgentActivityStatus) { - log.Tracef("DataplaneStatus: Removing %v from agentActivityStatuses", agentActivityStatus) - if _, ok := agentActivityStatus.GetStatus().(*proto.AgentActivityStatus_NginxConfigStatus); ok { - for index, agentActivityStatus := range dps.agentActivityStatuses { - if _, ok := agentActivityStatus.GetStatus().(*proto.AgentActivityStatus_NginxConfigStatus); ok { - dps.agentActivityStatuses = append(dps.agentActivityStatuses[:index], dps.agentActivityStatuses[index+1:]...) - log.Tracef("DataplaneStatus: Removed %v from agentActivityStatus", agentActivityStatus) - } - } + dps.nginxConfigActivityStatuses[newAgentActivityStatus.GetNginxConfigStatus().GetNginxId()] = newAgentActivityStatus } } @@ -205,12 +181,18 @@ func (dps *DataPlaneStatus) dataplaneStatus(forceDetails bool) *proto.DataplaneS processes := dps.env.Processes() log.Tracef("dataplaneStatus: processes %v", processes) forceDetails = forceDetails || time.Now().UTC().Add(-dps.reportInterval).After(dps.lastSendDetails) + + agentActivityStatuses := []*proto.AgentActivityStatus{} + for _, nginxConfigActivityStatus := range dps.nginxConfigActivityStatuses { + agentActivityStatuses = append(agentActivityStatuses, nginxConfigActivityStatus) + } + return &proto.DataplaneStatus{ Host: dps.hostInfo(forceDetails), Details: dps.detailsForProcess(processes, forceDetails), Healths: dps.healthForProcess(processes), DataplaneSoftwareDetails: dps.dataplaneSoftwareDetails(), - AgentActivityStatus: dps.agentActivityStatuses, + AgentActivityStatus: agentActivityStatuses, } } diff --git a/src/plugins/dataplane_status_test.go b/src/plugins/dataplane_status_test.go index a7a54ae39..6e06edacb 100644 --- a/src/plugins/dataplane_status_test.go +++ b/src/plugins/dataplane_status_test.go @@ -36,7 +36,9 @@ func TestDataPlaneStatus(t *testing.T) { expectedMessage: core.NewMessage(core.CommStatus, &proto.Command{ Meta: nil, Data: &proto.Command_DataplaneStatus{ - DataplaneStatus: &proto.DataplaneStatus{}, + DataplaneStatus: &proto.DataplaneStatus{ + AgentActivityStatus: []*proto.AgentActivityStatus{}, + }, }, }), }, diff --git a/src/plugins/nginx.go b/src/plugins/nginx.go index 86cb600d5..a111b4019 100644 --- a/src/plugins/nginx.go +++ b/src/plugins/nginx.go @@ -326,6 +326,7 @@ func (n *Nginx) writeConfigAndReloadNginx(correlationId string, config *proto.Ng CorrelationId: correlationId, Status: proto.NginxConfigStatus_PENDING, Message: "config apply pending", + NginxId: config.GetConfigData().GetNginxId(), }, }, })) @@ -521,6 +522,7 @@ func (n *Nginx) completeConfigApply(response *NginxConfigValidationResponse) *pr CorrelationId: response.correlationId, Status: proto.NginxConfigStatus_OK, Message: nginxConfigStatusMessage, + NginxId: response.config.GetConfigData().GetNginxId(), }, }, } @@ -574,6 +576,7 @@ func (n *Nginx) rollbackConfigApply(response *NginxConfigValidationResponse) { CorrelationId: response.correlationId, Status: proto.NginxConfigStatus_ERROR, Message: nginxConfigStatusMessage, + NginxId: response.config.GetConfigData().GetNginxId(), }, }, } diff --git a/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/command.pb.go b/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/command.pb.go index 9cd0046a2..1eb5da172 100644 --- a/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/command.pb.go +++ b/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/command.pb.go @@ -631,6 +631,7 @@ type NginxConfigStatus struct { CorrelationId string `protobuf:"bytes,1,opt,name=correlation_id,json=correlationId,proto3" json:"correlation_id"` Status NginxConfigStatus_Status `protobuf:"varint,2,opt,name=status,proto3,enum=f5.nginx.agent.sdk.NginxConfigStatus_Status" json:"status"` Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message"` + NginxId string `protobuf:"bytes,4,opt,name=nginx_id,json=nginxId,proto3" json:"nginx_id"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -690,6 +691,13 @@ func (m *NginxConfigStatus) GetMessage() string { return "" } +func (m *NginxConfigStatus) GetNginxId() string { + if m != nil { + return m.NginxId + } + return "" +} + type DataplaneSoftwareHealth struct { // Types that are valid to be assigned to Health: // *DataplaneSoftwareHealth_NginxHealth @@ -1253,103 +1261,103 @@ func init() { func init() { proto.RegisterFile("command.proto", fileDescriptor_213c0bb044472049) } var fileDescriptor_213c0bb044472049 = []byte{ - // 1521 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4d, 0x6f, 0xdb, 0xc6, - 0x16, 0x25, 0x15, 0xeb, 0xeb, 0x4a, 0xb6, 0x95, 0xb1, 0x93, 0x28, 0x46, 0x60, 0x1a, 0x7c, 0x2f, - 0x2f, 0xce, 0x7b, 0x79, 0x12, 0xea, 0xa0, 0x08, 0x9a, 0xac, 0x24, 0x4b, 0x09, 0x85, 0xc4, 0x92, - 0x31, 0x89, 0x13, 0x20, 0x45, 0x21, 0x30, 0xe2, 0x48, 0x16, 0x6c, 0x91, 0x2c, 0x49, 0x39, 0x71, - 0xd0, 0x7d, 0xd1, 0xa2, 0x9b, 0x2e, 0xba, 0x28, 0xfa, 0x23, 0xfa, 0x37, 0xba, 0xcc, 0xba, 0x0b, - 0xa2, 0xc8, 0x92, 0xbb, 0x6e, 0xda, 0x45, 0x37, 0xc5, 0x7c, 0x50, 0xa2, 0x24, 0x4a, 0x76, 0xea, - 0xa2, 0x1b, 0xce, 0x70, 0x78, 0xee, 0xb9, 0x77, 0xee, 0xcc, 0x9c, 0xb9, 0x12, 0x2c, 0x77, 0xac, - 0xc1, 0x40, 0x37, 0x8d, 0x92, 0xed, 0x58, 0x9e, 0x85, 0x50, 0xf7, 0xe3, 0x92, 0xd9, 0xeb, 0x9b, - 0x6f, 0x4a, 0x7a, 0x8f, 0x98, 0x5e, 0xc9, 0x35, 0x8e, 0x36, 0xa0, 0x67, 0xf5, 0x2c, 0xfe, 0x7d, - 0x23, 0x4f, 0xe1, 0x96, 0x29, 0xde, 0x72, 0x1c, 0xc4, 0x5f, 0xe0, 0xd0, 0x72, 0xc3, 0x7e, 0x8e, - 0x73, 0x8c, 0x6c, 0xcc, 0x6e, 0xbf, 0x27, 0xde, 0x10, 0x39, 0x21, 0xa6, 0xe7, 0x96, 0x59, 0x23, - 0xc6, 0xae, 0x1b, 0x76, 0xdb, 0xb5, 0xba, 0xde, 0x6b, 0xdd, 0x21, 0x6d, 0x83, 0x78, 0x7a, 0xff, - 0xd8, 0x15, 0x9f, 0xb2, 0xa6, 0x6e, 0xf3, 0xae, 0xfa, 0x07, 0x40, 0x7a, 0x97, 0x47, 0x8b, 0xee, - 0xc3, 0xd2, 0x80, 0x78, 0x7a, 0x51, 0xde, 0x92, 0xb7, 0x73, 0x3b, 0x37, 0x4a, 0xb3, 0x61, 0x97, - 0xf6, 0x88, 0xa7, 0x1b, 0xba, 0xa7, 0x57, 0x33, 0x81, 0xaf, 0x30, 0x34, 0x66, 0x4f, 0x54, 0x87, - 0x25, 0xef, 0xd4, 0x26, 0xc5, 0xc4, 0x96, 0xbc, 0xbd, 0xb2, 0x73, 0x2b, 0xce, 0x56, 0xb8, 0x09, - 0xdb, 0x67, 0xa7, 0x36, 0xe1, 0x34, 0xd4, 0x10, 0xb3, 0x27, 0x7a, 0x09, 0xd0, 0x19, 0x18, 0x6d, - 0xd7, 0xd3, 0xbd, 0xa1, 0x5b, 0xbc, 0xc4, 0x02, 0xb9, 0xbd, 0x80, 0xec, 0x29, 0x03, 0x62, 0xe2, - 0xda, 0x96, 0xe9, 0x92, 0xea, 0x4a, 0xe0, 0x2b, 0x11, 0x02, 0x4d, 0xc2, 0xd9, 0xce, 0x40, 0x80, - 0xd0, 0x73, 0xc8, 0x33, 0x96, 0x36, 0x4f, 0x5d, 0x71, 0x89, 0xb1, 0x2b, 0x71, 0xec, 0x4d, 0xfa, - 0xbe, 0xcb, 0x60, 0xd5, 0x42, 0xe0, 0x2b, 0x13, 0x86, 0x9a, 0x84, 0xf9, 0x52, 0x70, 0x00, 0x7a, - 0x03, 0x57, 0xa2, 0x9f, 0xdb, 0x8e, 0x88, 0xa6, 0x98, 0x64, 0x0e, 0x6e, 0x9d, 0xe1, 0x60, 0x14, - 0xfc, 0xf5, 0xc0, 0x57, 0xe2, 0x99, 0x34, 0x09, 0xaf, 0x99, 0xb3, 0x16, 0xd4, 0x33, 0xa3, 0xa4, - 0x78, 0x93, 0x74, 0xbc, 0xb6, 0x43, 0x3e, 0x1f, 0x12, 0xd7, 0x2b, 0xa6, 0xe6, 0x7b, 0xae, 0xd0, - 0xde, 0x2e, 0xc7, 0x63, 0x0e, 0xe7, 0x9e, 0x63, 0x99, 0xa8, 0x67, 0x7d, 0xd6, 0x02, 0x7d, 0x01, - 0x57, 0xa7, 0xf1, 0x62, 0xd2, 0x69, 0xe6, 0x7a, 0xfb, 0x6c, 0xd7, 0x62, 0xd6, 0x1b, 0x81, 0xaf, - 0xcc, 0xe1, 0xd2, 0x24, 0xbc, 0xae, 0xc7, 0xd8, 0x20, 0x0f, 0xd6, 0x47, 0x16, 0x3c, 0x4f, 0x7c, - 0xda, 0x19, 0xe6, 0xfb, 0x3f, 0x8b, 0x7c, 0xb3, 0xf4, 0xf1, 0x59, 0x17, 0x03, 0x5f, 0x89, 0xe5, - 0xd1, 0x24, 0x8c, 0xf4, 0x19, 0x3c, 0xdd, 0x3f, 0x51, 0x74, 0x31, 0x3b, 0x7f, 0xff, 0x44, 0xbc, - 0xf1, 0xfd, 0x13, 0x35, 0xa4, 0xfb, 0x27, 0x42, 0x8f, 0xba, 0x50, 0xa0, 0x47, 0xca, 0x3e, 0xd6, - 0x4d, 0x12, 0xee, 0xfc, 0x1c, 0xe3, 0xfe, 0x57, 0x1c, 0x77, 0x2d, 0xc4, 0xf2, 0x6d, 0x5d, 0x5d, - 0x0f, 0x7c, 0x65, 0x86, 0x40, 0x93, 0xf0, 0xaa, 0x31, 0x09, 0x44, 0x9f, 0x41, 0x9e, 0xe9, 0x43, - 0xdb, 0x21, 0xb6, 0xe5, 0x78, 0xc5, 0xfc, 0xfc, 0x6c, 0x71, 0x39, 0x29, 0xd5, 0x69, 0x83, 0x19, - 0x9a, 0x4f, 0x23, 0x6a, 0x4f, 0xa7, 0x41, 0xc6, 0x00, 0xf4, 0x8d, 0x0c, 0x1b, 0x91, 0x30, 0xa6, - 0x94, 0xa7, 0xb8, 0xcc, 0xbc, 0xdd, 0x59, 0x3c, 0x23, 0x61, 0x54, 0xe3, 0x36, 0xd5, 0xcd, 0xc0, - 0x57, 0x16, 0x70, 0x6a, 0x12, 0x2e, 0x1a, 0x73, 0x6c, 0x27, 0xb3, 0x3a, 0xb4, 0x0d, 0xdd, 0x23, - 0xc5, 0x95, 0x73, 0x64, 0xf5, 0x80, 0x41, 0xa7, 0xb3, 0xca, 0x09, 0x26, 0xb2, 0xca, 0x81, 0xea, - 0x5d, 0xc8, 0x45, 0x04, 0x0d, 0x01, 0xa4, 0x9a, 0x2d, 0xbc, 0x57, 0x79, 0x52, 0x90, 0x50, 0x1e, - 0x32, 0xb5, 0xd6, 0x8b, 0xe6, 0x93, 0x56, 0xa5, 0x56, 0x90, 0xe9, 0x97, 0x83, 0x7d, 0xd6, 0x4f, - 0x54, 0x53, 0xb0, 0x44, 0x79, 0xd4, 0xef, 0x2e, 0xc1, 0x95, 0x58, 0x25, 0x43, 0x9f, 0x42, 0x4a, - 0x6c, 0x05, 0x99, 0x29, 0xea, 0xbd, 0x73, 0x8b, 0xe0, 0xe4, 0x68, 0x15, 0x02, 0x5f, 0x11, 0x54, - 0x58, 0xb4, 0xa8, 0x0f, 0x40, 0x1c, 0xc7, 0x72, 0xda, 0x1d, 0xcb, 0x08, 0x25, 0xfb, 0xfe, 0x07, - 0x3b, 0xa8, 0x53, 0x8a, 0x5d, 0xcb, 0x10, 0xb2, 0x3b, 0x66, 0xc4, 0x59, 0x12, 0x7e, 0x42, 0x37, - 0x21, 0x3d, 0x20, 0xae, 0xab, 0xf7, 0x08, 0x53, 0xf3, 0x6c, 0x35, 0x17, 0xf8, 0x4a, 0x38, 0x84, - 0xc3, 0x0e, 0x52, 0x20, 0xc9, 0x6c, 0x98, 0x28, 0x67, 0xab, 0xd9, 0xc0, 0x57, 0xf8, 0x00, 0xe6, - 0x8d, 0xfa, 0x00, 0x96, 0x27, 0x82, 0x41, 0xab, 0x90, 0xdb, 0xdd, 0xab, 0xb5, 0x0f, 0x9a, 0x8f, - 0x9b, 0xad, 0x17, 0xcd, 0x82, 0x44, 0xf3, 0x4b, 0x07, 0x5a, 0x8f, 0x0b, 0x32, 0x5a, 0x86, 0x2c, - 0xed, 0xd7, 0x31, 0x6e, 0xe1, 0x42, 0x42, 0x2d, 0x43, 0x61, 0x3a, 0x66, 0x0a, 0xaf, 0x63, 0x4c, - 0xe1, 0x12, 0xe5, 0xa2, 0xfd, 0x90, 0x4b, 0x56, 0x7f, 0x48, 0xc2, 0xea, 0xd4, 0x39, 0x43, 0xff, - 0x85, 0xac, 0x7b, 0xea, 0x7a, 0x64, 0xd0, 0xee, 0x1b, 0x6c, 0x51, 0xb2, 0xd5, 0xe5, 0xc0, 0x57, - 0xc6, 0x83, 0x38, 0xc3, 0xbb, 0x0d, 0x03, 0x3d, 0x82, 0x74, 0xb8, 0xef, 0x13, 0x5b, 0x97, 0xb6, - 0x73, 0x3b, 0x5b, 0x73, 0x2f, 0x81, 0x70, 0xaf, 0xb3, 0xbc, 0x08, 0x23, 0x1c, 0x76, 0xe8, 0x95, - 0x4c, 0x2b, 0x00, 0x71, 0x13, 0xc6, 0x5e, 0xc9, 0x9a, 0xe5, 0x7a, 0x0d, 0xb3, 0x6b, 0xf1, 0xbb, - 0x94, 0xa2, 0x31, 0x7b, 0xa2, 0x87, 0x90, 0x3e, 0x24, 0xfa, 0xb1, 0x77, 0xe8, 0x16, 0x93, 0x2c, - 0x88, 0xf9, 0x57, 0x9d, 0xc6, 0x70, 0x3c, 0x06, 0x61, 0x83, 0xc3, 0x0e, 0xfa, 0x7a, 0xf1, 0xc1, - 0x4e, 0x31, 0xee, 0xbf, 0xf5, 0x60, 0x2f, 0x38, 0xd6, 0x5f, 0xc5, 0x07, 0x13, 0x4e, 0x34, 0xcd, - 0x82, 0xf9, 0xdf, 0xb9, 0x82, 0x11, 0x93, 0x9e, 0x17, 0x4b, 0x98, 0x87, 0xd9, 0x58, 0x34, 0x91, - 0x98, 0x93, 0xf0, 0xfa, 0xd5, 0x3b, 0x5e, 0xff, 0xa4, 0xef, 0x9d, 0x86, 0xea, 0x9d, 0x61, 0x51, - 0xcc, 0xbf, 0x7e, 0x2b, 0x02, 0x2f, 0x8e, 0x68, 0xe4, 0xfa, 0x9d, 0x62, 0x12, 0x97, 0xef, 0x24, - 0x5e, 0xfd, 0x56, 0x86, 0xb5, 0x18, 0x1e, 0x64, 0xc3, 0xda, 0x44, 0xf9, 0x10, 0x11, 0x90, 0xdc, - 0xce, 0xcd, 0x33, 0xca, 0x10, 0x11, 0xcb, 0xb5, 0xc0, 0x57, 0xe2, 0x58, 0x34, 0x09, 0x5f, 0x36, - 0x67, 0xd0, 0x19, 0x48, 0x89, 0x98, 0x7e, 0x95, 0xe1, 0xf2, 0x0c, 0x1b, 0xfa, 0x04, 0x56, 0x3a, - 0x96, 0xe3, 0x90, 0x63, 0xdd, 0xeb, 0x5b, 0xe6, 0xf8, 0xe0, 0xa0, 0xc0, 0x57, 0xa6, 0xbe, 0xe0, - 0xe5, 0xc8, 0x7b, 0xc3, 0x40, 0xfb, 0x23, 0x01, 0xe4, 0xfa, 0x74, 0xe7, 0x5c, 0xf1, 0x97, 0x16, - 0xa8, 0xde, 0xf9, 0xa4, 0x48, 0xdd, 0x0e, 0xe7, 0x84, 0x72, 0x90, 0xde, 0xaf, 0x37, 0x6b, 0x8d, - 0xe6, 0xa3, 0x82, 0x84, 0x52, 0x90, 0x60, 0xd2, 0x92, 0x85, 0x64, 0x28, 0x2b, 0xbf, 0xcb, 0x70, - 0x6d, 0xce, 0xae, 0x1a, 0x17, 0x9b, 0x7c, 0x1b, 0x89, 0x45, 0x38, 0xf3, 0x04, 0x46, 0x8a, 0x4d, - 0x6e, 0x38, 0x2a, 0x36, 0x05, 0xef, 0x5b, 0xb8, 0xaa, 0xdb, 0x76, 0x9b, 0x16, 0xef, 0xb4, 0x54, - 0x7a, 0xad, 0x77, 0x43, 0x0f, 0x89, 0x05, 0x35, 0x9f, 0x6d, 0xef, 0x73, 0x83, 0x17, 0x95, 0x87, - 0xc2, 0x13, 0xaf, 0xbb, 0x62, 0xa9, 0x58, 0xd1, 0x37, 0x36, 0xd1, 0xbb, 0xc2, 0x24, 0x03, 0x29, - 0x0e, 0x50, 0x7f, 0x96, 0x23, 0xfa, 0xc8, 0x2f, 0xc2, 0x91, 0x54, 0xc9, 0x7f, 0x41, 0xaa, 0xce, - 0x90, 0x98, 0xc4, 0x3f, 0x29, 0x31, 0xea, 0x1e, 0xac, 0xd6, 0xac, 0xd7, 0xe6, 0xb1, 0xa5, 0x1b, - 0x61, 0xe9, 0x77, 0x81, 0x5f, 0x46, 0xea, 0x97, 0x09, 0x58, 0x8b, 0x29, 0xf7, 0xd1, 0xde, 0xc4, - 0x0d, 0xff, 0x41, 0x3f, 0x73, 0xe2, 0x76, 0x77, 0x03, 0x52, 0x54, 0x3c, 0x2c, 0x53, 0x9c, 0x97, - 0xb3, 0xce, 0x7b, 0x85, 0x81, 0x39, 0x15, 0x37, 0xc4, 0xa2, 0x45, 0xcf, 0x21, 0x27, 0xce, 0x3e, - 0x9d, 0x90, 0xb8, 0x7b, 0xfe, 0x1d, 0x1f, 0x1e, 0x85, 0xd5, 0x88, 0xdb, 0x71, 0xfa, 0xb6, 0x67, - 0x39, 0xd5, 0xd5, 0xc0, 0x57, 0xa2, 0xc6, 0x18, 0xf8, 0x0b, 0x5d, 0x26, 0xf5, 0x37, 0x19, 0xf2, - 0x07, 0x36, 0xcd, 0xab, 0x38, 0x60, 0x17, 0xf9, 0xc1, 0xf9, 0x74, 0x4a, 0x1f, 0xca, 0x71, 0xd6, - 0x51, 0x6f, 0xa5, 0x67, 0x8e, 0x6e, 0xba, 0x5d, 0xe2, 0x2c, 0x90, 0x08, 0x15, 0x52, 0x0e, 0xd1, - 0x5d, 0xcb, 0x14, 0x0a, 0xc1, 0x30, 0x7c, 0x04, 0x8b, 0x56, 0xfd, 0x08, 0x56, 0x26, 0x99, 0xa8, - 0x4e, 0x8c, 0xcb, 0x90, 0x50, 0x27, 0x00, 0x52, 0x0f, 0x2b, 0x8d, 0x27, 0xf5, 0x5a, 0x21, 0xa1, - 0xfe, 0x28, 0x43, 0x96, 0x66, 0x60, 0xf7, 0x70, 0x68, 0x1e, 0xa1, 0x16, 0x3b, 0x46, 0x06, 0x71, - 0x16, 0x2e, 0x3c, 0x85, 0x12, 0x03, 0x13, 0xd7, 0x1a, 0x3a, 0x1d, 0xaa, 0x2a, 0x06, 0x71, 0x78, - 0x3c, 0xdc, 0x58, 0x93, 0xb0, 0xe8, 0x21, 0x8d, 0x57, 0x93, 0x42, 0x01, 0xb6, 0xcf, 0x41, 0xc7, - 0x5e, 0x79, 0x4a, 0xa9, 0xa5, 0x26, 0x61, 0xd6, 0x56, 0xd3, 0x90, 0xec, 0xd0, 0x4f, 0xea, 0x3b, - 0x19, 0xae, 0xc4, 0x86, 0x70, 0xa1, 0x35, 0x53, 0x21, 0xc5, 0xe8, 0xf9, 0x9a, 0x25, 0xf9, 0x74, - 0xf8, 0x08, 0x16, 0x2d, 0xda, 0x86, 0x4c, 0xe7, 0x90, 0x74, 0x8e, 0xdc, 0xe1, 0x40, 0x2c, 0x42, - 0x3e, 0xf0, 0x95, 0xd1, 0x18, 0x1e, 0xf5, 0xd0, 0xff, 0x01, 0x98, 0x4d, 0xdb, 0xed, 0xbf, 0x25, - 0xac, 0x70, 0x4c, 0x8a, 0x3f, 0x00, 0x46, 0xa3, 0x38, 0xcb, 0xfa, 0x4f, 0xfb, 0x6f, 0x89, 0xfa, - 0xbd, 0x0c, 0xeb, 0x71, 0x69, 0xb8, 0xd0, 0x8c, 0x6e, 0xd1, 0x68, 0xa9, 0xb7, 0xbe, 0x21, 0xe6, - 0x24, 0xa2, 0xe5, 0x63, 0x38, 0xcd, 0x7a, 0x0d, 0x03, 0xdd, 0x10, 0x6b, 0x44, 0xa7, 0x94, 0x1f, - 0x67, 0x5e, 0xe4, 0xfd, 0xde, 0x4f, 0xef, 0x37, 0xe5, 0x77, 0xef, 0x37, 0xe5, 0x5f, 0xde, 0x6f, - 0xca, 0x2f, 0x6f, 0xf7, 0xfa, 0xde, 0xe1, 0xf0, 0x55, 0xa9, 0x63, 0x0d, 0xca, 0x2c, 0x92, 0x32, - 0x8b, 0xa4, 0xec, 0x1a, 0x47, 0xe5, 0x93, 0x9d, 0x32, 0xfb, 0xe3, 0xe6, 0x01, 0x7b, 0xbe, 0x4a, - 0xb1, 0xe6, 0xee, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc3, 0xee, 0xd6, 0x35, 0x72, 0x12, 0x00, - 0x00, + // 1535 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcb, 0x6e, 0xdb, 0x46, + 0x17, 0x26, 0x15, 0xeb, 0x76, 0x24, 0xdb, 0xca, 0xd8, 0x49, 0x14, 0x23, 0x30, 0x0d, 0xfe, 0x7f, + 0x6a, 0xa7, 0x4d, 0x25, 0xd4, 0x41, 0x11, 0x34, 0x59, 0x59, 0x96, 0x13, 0x0a, 0x89, 0x65, 0x63, + 0x12, 0x27, 0x40, 0x8a, 0x42, 0x60, 0xc4, 0x91, 0x4c, 0xd8, 0x22, 0x59, 0x92, 0x72, 0xe2, 0xa0, + 0xfb, 0xa2, 0x45, 0x37, 0x5d, 0x74, 0xd1, 0xf6, 0x21, 0xfa, 0x1a, 0x5d, 0x66, 0xdd, 0x05, 0x51, + 0x64, 0xc9, 0x07, 0x68, 0x17, 0xdd, 0x14, 0x73, 0xa1, 0x44, 0x49, 0x94, 0xec, 0xd4, 0x45, 0x37, + 0x9a, 0xe1, 0xf0, 0x3b, 0xdf, 0xb9, 0xcc, 0xcc, 0x37, 0x43, 0xc1, 0x7c, 0xdb, 0xee, 0xf5, 0x74, + 0xcb, 0xa8, 0x38, 0xae, 0xed, 0xdb, 0x08, 0x75, 0x3e, 0xad, 0x58, 0x5d, 0xd3, 0x7a, 0x5d, 0xd1, + 0xbb, 0xc4, 0xf2, 0x2b, 0x9e, 0x71, 0xb4, 0x02, 0x5d, 0xbb, 0x6b, 0xf3, 0xf7, 0x2b, 0x45, 0x0a, + 0xb7, 0x2d, 0xf1, 0x54, 0xe0, 0x20, 0xfe, 0x00, 0x87, 0xb6, 0x17, 0xf5, 0x0b, 0x9c, 0x63, 0x60, + 0x63, 0x75, 0xcc, 0xae, 0x78, 0x42, 0xe4, 0x84, 0x58, 0xbe, 0x57, 0x65, 0x8d, 0x18, 0xbb, 0x6e, + 0x38, 0x2d, 0xcf, 0xee, 0xf8, 0xaf, 0x74, 0x97, 0xb4, 0x0c, 0xe2, 0xeb, 0xe6, 0xb1, 0x27, 0x5e, + 0xe5, 0x2d, 0xdd, 0xe1, 0x5d, 0xf5, 0x2f, 0x80, 0xec, 0x36, 0x8f, 0x16, 0xdd, 0x83, 0xb9, 0x1e, + 0xf1, 0xf5, 0xb2, 0xbc, 0x26, 0x6f, 0x14, 0x36, 0x6f, 0x54, 0x26, 0xc3, 0xae, 0xec, 0x12, 0x5f, + 0x37, 0x74, 0x5f, 0xaf, 0xe5, 0xc2, 0x40, 0x61, 0x68, 0xcc, 0x7e, 0xd1, 0x0e, 0xcc, 0xf9, 0xa7, + 0x0e, 0x29, 0xa7, 0xd6, 0xe4, 0x8d, 0x85, 0xcd, 0xf5, 0x24, 0x5b, 0xe1, 0x26, 0x6a, 0x9f, 0x9e, + 0x3a, 0x84, 0xd3, 0x50, 0x43, 0xcc, 0x7e, 0xd1, 0x0b, 0x80, 0x76, 0xcf, 0x68, 0x79, 0xbe, 0xee, + 0xf7, 0xbd, 0xf2, 0x25, 0x16, 0xc8, 0xad, 0x19, 0x64, 0x4f, 0x18, 0x10, 0x13, 0xcf, 0xb1, 0x2d, + 0x8f, 0xd4, 0x16, 0xc2, 0x40, 0x89, 0x11, 0x68, 0x12, 0xce, 0xb7, 0x7b, 0x02, 0x84, 0x9e, 0x41, + 0x91, 0xb1, 0xb4, 0x78, 0xe9, 0xca, 0x73, 0x8c, 0x5d, 0x49, 0x62, 0x6f, 0xd2, 0xe7, 0x6d, 0x06, + 0xab, 0x95, 0xc2, 0x40, 0x19, 0x31, 0xd4, 0x24, 0xcc, 0xa7, 0x82, 0x03, 0xd0, 0x6b, 0xb8, 0x12, + 0x7f, 0xdd, 0x72, 0x45, 0x34, 0xe5, 0x34, 0x73, 0xb0, 0x7e, 0x86, 0x83, 0x41, 0xf0, 0xd7, 0xc3, + 0x40, 0x49, 0x66, 0xd2, 0x24, 0xbc, 0x64, 0x4d, 0x5a, 0x50, 0xcf, 0x8c, 0x92, 0xe2, 0x2d, 0xd2, + 0xf6, 0x5b, 0x2e, 0xf9, 0xb2, 0x4f, 0x3c, 0xbf, 0x9c, 0x99, 0xee, 0x79, 0x8b, 0xf6, 0xb6, 0x39, + 0x1e, 0x73, 0x38, 0xf7, 0x9c, 0xc8, 0x44, 0x3d, 0xeb, 0x93, 0x16, 0xe8, 0x2b, 0xb8, 0x3a, 0x8e, + 0x17, 0x49, 0x67, 0x99, 0xeb, 0x8d, 0xb3, 0x5d, 0x8b, 0xac, 0x57, 0xc2, 0x40, 0x99, 0xc2, 0xa5, + 0x49, 0x78, 0x59, 0x4f, 0xb0, 0x41, 0x3e, 0x2c, 0x0f, 0x2c, 0x78, 0x9d, 0x78, 0xda, 0x39, 0xe6, + 0xfb, 0x83, 0x59, 0xbe, 0x59, 0xf9, 0x78, 0xd6, 0xe5, 0x30, 0x50, 0x12, 0x79, 0x34, 0x09, 0x23, + 0x7d, 0x02, 0x4f, 0xd7, 0x4f, 0x1c, 0x5d, 0xce, 0x4f, 0x5f, 0x3f, 0x31, 0x6f, 0x7c, 0xfd, 0xc4, + 0x0d, 0xe9, 0xfa, 0x89, 0xd1, 0xa3, 0x0e, 0x94, 0xe8, 0x96, 0x72, 0x8e, 0x75, 0x8b, 0x44, 0x2b, + 0xbf, 0xc0, 0xb8, 0xff, 0x97, 0xc4, 0x5d, 0x8f, 0xb0, 0x7c, 0x59, 0xd7, 0x96, 0xc3, 0x40, 0x99, + 0x20, 0xd0, 0x24, 0xbc, 0x68, 0x8c, 0x02, 0xd1, 0x17, 0x50, 0x64, 0xfa, 0xd0, 0x72, 0x89, 0x63, + 0xbb, 0x7e, 0xb9, 0x38, 0xbd, 0x5a, 0x5c, 0x4e, 0x2a, 0x3b, 0xb4, 0xc1, 0x0c, 0xcd, 0xd3, 0x88, + 0xdb, 0xd3, 0x34, 0xc8, 0x10, 0x80, 0xbe, 0x93, 0x61, 0x25, 0x16, 0xc6, 0x98, 0xf2, 0x94, 0xe7, + 0x99, 0xb7, 0xdb, 0xb3, 0x33, 0x12, 0x46, 0x75, 0x6e, 0x53, 0x5b, 0x0d, 0x03, 0x65, 0x06, 0xa7, + 0x26, 0xe1, 0xb2, 0x31, 0xc5, 0x76, 0xb4, 0xaa, 0x7d, 0xc7, 0xd0, 0x7d, 0x52, 0x5e, 0x38, 0x47, + 0x55, 0x0f, 0x18, 0x74, 0xbc, 0xaa, 0x9c, 0x60, 0xa4, 0xaa, 0x1c, 0xa8, 0xde, 0x81, 0x42, 0x4c, + 0xd0, 0x10, 0x40, 0xa6, 0xb9, 0x87, 0x77, 0xb7, 0x1e, 0x97, 0x24, 0x54, 0x84, 0x5c, 0x7d, 0xef, + 0x79, 0xf3, 0xf1, 0xde, 0x56, 0xbd, 0x24, 0xd3, 0x37, 0x07, 0xfb, 0xac, 0x9f, 0xaa, 0x65, 0x60, + 0x8e, 0xf2, 0xa8, 0x3f, 0x5c, 0x82, 0x2b, 0x89, 0x4a, 0x86, 0x3e, 0x87, 0x8c, 0x58, 0x0a, 0x32, + 0x53, 0xd4, 0xbb, 0xe7, 0x16, 0xc1, 0xd1, 0xd1, 0x1a, 0x84, 0x81, 0x22, 0xa8, 0xb0, 0x68, 0x91, + 0x09, 0x40, 0x5c, 0xd7, 0x76, 0x5b, 0x6d, 0xdb, 0x88, 0x24, 0xfb, 0xde, 0x7b, 0x3b, 0xd8, 0xa1, + 0x14, 0xdb, 0xb6, 0x21, 0x64, 0x77, 0xc8, 0x88, 0xf3, 0x24, 0x7a, 0x85, 0x6e, 0x42, 0xb6, 0x47, + 0x3c, 0x4f, 0xef, 0x12, 0xa6, 0xe6, 0xf9, 0x5a, 0x21, 0x0c, 0x94, 0x68, 0x08, 0x47, 0x1d, 0xa4, + 0x40, 0x9a, 0xd9, 0x30, 0x51, 0xce, 0xd7, 0xf2, 0x61, 0xa0, 0xf0, 0x01, 0xcc, 0x1b, 0xf5, 0x3e, + 0xcc, 0x8f, 0x04, 0x83, 0x16, 0xa1, 0xb0, 0xbd, 0x5b, 0x6f, 0x1d, 0x34, 0x1f, 0x35, 0xf7, 0x9e, + 0x37, 0x4b, 0x12, 0xad, 0x2f, 0x1d, 0xd8, 0x7b, 0x54, 0x92, 0xd1, 0x3c, 0xe4, 0x69, 0x7f, 0x07, + 0xe3, 0x3d, 0x5c, 0x4a, 0xa9, 0x55, 0x28, 0x8d, 0xc7, 0x4c, 0xe1, 0x3b, 0x18, 0x53, 0xb8, 0x44, + 0xb9, 0x68, 0x3f, 0xe2, 0x92, 0xd5, 0x9f, 0xd3, 0xb0, 0x38, 0xb6, 0xcf, 0xd0, 0x87, 0x90, 0xf7, + 0x4e, 0x3d, 0x9f, 0xf4, 0x5a, 0xa6, 0xc1, 0x26, 0x25, 0x5f, 0x9b, 0x0f, 0x03, 0x65, 0x38, 0x88, + 0x73, 0xbc, 0xdb, 0x30, 0xd0, 0x43, 0xc8, 0x46, 0xeb, 0x3e, 0xb5, 0x76, 0x69, 0xa3, 0xb0, 0xb9, + 0x36, 0xf5, 0x10, 0x88, 0xd6, 0x3a, 0xab, 0x8b, 0x30, 0xc2, 0x51, 0x87, 0x1e, 0xc9, 0xf4, 0x06, + 0x20, 0x4e, 0xc2, 0xc4, 0x23, 0x59, 0xb3, 0x3d, 0xbf, 0x61, 0x75, 0x6c, 0x7e, 0x96, 0x52, 0x34, + 0x66, 0xbf, 0xe8, 0x01, 0x64, 0x0f, 0x89, 0x7e, 0xec, 0x1f, 0x7a, 0xe5, 0x34, 0x0b, 0x62, 0xfa, + 0x51, 0xa7, 0x31, 0x1c, 0x8f, 0x41, 0xd8, 0xe0, 0xa8, 0x83, 0xbe, 0x9d, 0xbd, 0xb1, 0x33, 0x8c, + 0xfb, 0x5f, 0xdd, 0xd8, 0x33, 0xb6, 0xf5, 0x37, 0xc9, 0xc1, 0x44, 0x89, 0x66, 0x59, 0x30, 0x1f, + 0x9d, 0x2b, 0x18, 0x91, 0xf4, 0xb4, 0x58, 0xa2, 0x3a, 0x4c, 0xc6, 0xa2, 0x89, 0xc2, 0x9c, 0x44, + 0xc7, 0xaf, 0xde, 0xf6, 0xcd, 0x13, 0xd3, 0x3f, 0x8d, 0xd4, 0x3b, 0xc7, 0xa2, 0x98, 0x7e, 0xfc, + 0x6e, 0x09, 0xbc, 0xd8, 0xa2, 0xb1, 0xe3, 0x77, 0x8c, 0x49, 0x1c, 0xbe, 0xa3, 0x78, 0xf5, 0x7b, + 0x19, 0x96, 0x12, 0x78, 0x90, 0x03, 0x4b, 0x23, 0xd7, 0x87, 0x98, 0x80, 0x14, 0x36, 0x6f, 0x9e, + 0x71, 0x0d, 0x11, 0xb1, 0x5c, 0x0b, 0x03, 0x25, 0x89, 0x45, 0x93, 0xf0, 0x65, 0x6b, 0x02, 0x9d, + 0x83, 0x8c, 0x88, 0xe9, 0xa7, 0x14, 0x5c, 0x9e, 0x60, 0x43, 0x9f, 0xc1, 0x42, 0xdb, 0x76, 0x5d, + 0x72, 0xac, 0xfb, 0xa6, 0x6d, 0x0d, 0x37, 0x0e, 0x0a, 0x03, 0x65, 0xec, 0x0d, 0x9e, 0x8f, 0x3d, + 0x37, 0x0c, 0xb4, 0x3f, 0x10, 0x40, 0xae, 0x4f, 0xb7, 0xcf, 0x15, 0x7f, 0x65, 0x86, 0xea, 0x9d, + 0x53, 0x8a, 0xd6, 0x21, 0xc7, 0xf3, 0x37, 0x0d, 0xa1, 0x46, 0xc5, 0x30, 0x50, 0x06, 0x63, 0x38, + 0xcb, 0x7a, 0x0d, 0x43, 0xdd, 0x88, 0x92, 0x47, 0x05, 0xc8, 0xee, 0xef, 0x34, 0xeb, 0x8d, 0xe6, + 0xc3, 0x92, 0x84, 0x32, 0x90, 0x62, 0x1a, 0x94, 0x87, 0x74, 0xa4, 0x3f, 0x7f, 0xca, 0x70, 0x6d, + 0xca, 0xf2, 0x1b, 0xde, 0x4a, 0xf9, 0x7a, 0x13, 0xb3, 0x75, 0xe6, 0x56, 0x8d, 0xdd, 0x4a, 0xb9, + 0xe1, 0xe0, 0x56, 0x2a, 0x78, 0xdf, 0xc0, 0x55, 0xdd, 0x71, 0x5a, 0xf4, 0x96, 0x4f, 0xef, 0x54, + 0xaf, 0xf4, 0x4e, 0xe4, 0x21, 0x35, 0xe3, 0x72, 0xe8, 0x38, 0xfb, 0xdc, 0xe0, 0xf9, 0xd6, 0x03, + 0xe1, 0x89, 0x5f, 0xd0, 0x12, 0xa9, 0xd8, 0xed, 0x70, 0x68, 0xa2, 0x77, 0x84, 0x49, 0x0e, 0x32, + 0x1c, 0xa0, 0xfe, 0x26, 0xc7, 0x84, 0x94, 0x9f, 0x98, 0x03, 0x4d, 0x93, 0xff, 0x81, 0xa6, 0x9d, + 0xa1, 0x45, 0xa9, 0xff, 0x52, 0x8b, 0xd4, 0x5d, 0x58, 0xac, 0xdb, 0xaf, 0xac, 0x63, 0x5b, 0x37, + 0xa2, 0x3b, 0xe2, 0x05, 0x3e, 0xa1, 0xd4, 0xaf, 0x53, 0xb0, 0x94, 0xf0, 0x5d, 0x80, 0x76, 0x47, + 0xae, 0x02, 0xef, 0xf5, 0x3d, 0x94, 0xb4, 0x0d, 0x1a, 0x90, 0xa1, 0x2a, 0x63, 0x5b, 0x62, 0x63, + 0x9d, 0x25, 0x0c, 0x5b, 0x0c, 0xcc, 0xa9, 0xb8, 0x21, 0x16, 0x2d, 0x7a, 0x06, 0x05, 0x21, 0x12, + 0x34, 0x21, 0x71, 0x48, 0xfd, 0x3f, 0x39, 0x3c, 0x0a, 0xab, 0x13, 0xaf, 0xed, 0x9a, 0x8e, 0x6f, + 0xbb, 0xb5, 0xc5, 0x30, 0x50, 0xe2, 0xc6, 0x18, 0xf8, 0x03, 0x9d, 0x26, 0xf5, 0x0f, 0x19, 0x8a, + 0x07, 0x0e, 0xad, 0xab, 0xd8, 0x60, 0x17, 0xf9, 0x32, 0x7d, 0x32, 0x26, 0x24, 0xd5, 0x24, 0xeb, + 0xb8, 0xb7, 0xca, 0x53, 0x57, 0xb7, 0xbc, 0x0e, 0x71, 0x67, 0x68, 0x89, 0x0a, 0x19, 0x97, 0xe8, + 0x9e, 0x6d, 0x09, 0x29, 0x61, 0x18, 0x3e, 0x82, 0x45, 0xab, 0x7e, 0x02, 0x0b, 0xa3, 0x4c, 0x54, + 0x27, 0x86, 0xf7, 0x95, 0x48, 0x27, 0x00, 0x32, 0x0f, 0xb6, 0x1a, 0x8f, 0x77, 0xea, 0xa5, 0x94, + 0xfa, 0x8b, 0x0c, 0x79, 0x5a, 0x81, 0xed, 0xc3, 0xbe, 0x75, 0x84, 0xf6, 0xd8, 0x36, 0x32, 0x88, + 0x3b, 0x73, 0xe2, 0x29, 0x94, 0x18, 0x98, 0x78, 0x76, 0xdf, 0x6d, 0x53, 0x55, 0x31, 0x88, 0xcb, + 0xe3, 0xe1, 0xc6, 0x9a, 0x84, 0x45, 0x0f, 0x69, 0xfc, 0xda, 0x29, 0x14, 0x60, 0xe3, 0x1c, 0x74, + 0xec, 0x91, 0x97, 0x94, 0x5a, 0x6a, 0x12, 0x66, 0x6d, 0x2d, 0x0b, 0xe9, 0x36, 0x7d, 0xa5, 0xbe, + 0x95, 0xe1, 0x4a, 0x62, 0x08, 0x17, 0x9a, 0x33, 0x15, 0x32, 0x8c, 0x9e, 0xcf, 0x59, 0x9a, 0xa7, + 0xc3, 0x47, 0xb0, 0x68, 0xd1, 0x06, 0xe4, 0xda, 0x87, 0xa4, 0x7d, 0xe4, 0xf5, 0x7b, 0x62, 0x12, + 0x98, 0x4e, 0x47, 0x63, 0x78, 0xd0, 0x43, 0x1f, 0x03, 0x30, 0x9b, 0x96, 0x67, 0xbe, 0x21, 0x4c, + 0xd3, 0xd3, 0xe2, 0x9f, 0x82, 0xc1, 0x28, 0xce, 0xb3, 0xfe, 0x13, 0xf3, 0x0d, 0x51, 0x7f, 0x94, + 0x61, 0x39, 0xa9, 0x0c, 0x17, 0xca, 0x68, 0x9d, 0x46, 0x4b, 0xbd, 0x99, 0x86, 0xc8, 0x49, 0x44, + 0xcb, 0xc7, 0x70, 0x96, 0xf5, 0x1a, 0x06, 0xba, 0x21, 0xe6, 0x88, 0xa6, 0x54, 0x1c, 0x56, 0x5e, + 0xd4, 0xfd, 0xee, 0xaf, 0xef, 0x56, 0xe5, 0xb7, 0xef, 0x56, 0xe5, 0xdf, 0xdf, 0xad, 0xca, 0x2f, + 0x6e, 0x75, 0x4d, 0xff, 0xb0, 0xff, 0xb2, 0xd2, 0xb6, 0x7b, 0x55, 0x16, 0x49, 0x95, 0x45, 0x52, + 0xf5, 0x8c, 0xa3, 0xea, 0xc9, 0x66, 0x95, 0xfd, 0xc3, 0x73, 0x9f, 0xfd, 0xbe, 0xcc, 0xb0, 0xe6, + 0xce, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x1f, 0x57, 0x17, 0x9b, 0x12, 0x00, 0x00, } func (m *Command) Marshal() (dAtA []byte, err error) { @@ -1884,6 +1892,13 @@ func (m *NginxConfigStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.NginxId) > 0 { + i -= len(m.NginxId) + copy(dAtA[i:], m.NginxId) + i = encodeVarintCommand(dAtA, i, uint64(len(m.NginxId))) + i-- + dAtA[i] = 0x22 + } if len(m.Message) > 0 { i -= len(m.Message) copy(dAtA[i:], m.Message) @@ -2653,6 +2668,10 @@ func (m *NginxConfigStatus) Size() (n int) { if l > 0 { n += 1 + l + sovCommand(uint64(l)) } + l = len(m.NginxId) + if l > 0 { + n += 1 + l + sovCommand(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -4007,6 +4026,38 @@ func (m *NginxConfigStatus) Unmarshal(dAtA []byte) error { } m.Message = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NginxId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommand + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommand + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommand + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NginxId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipCommand(dAtA[iNdEx:]) diff --git a/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/command.proto b/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/command.proto index 4ae215aa5..feb738c3c 100644 --- a/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/command.proto +++ b/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/command.proto @@ -103,6 +103,7 @@ message NginxConfigStatus { string correlation_id = 1 [(gogoproto.jsontag) = "correlation_id" ]; Status status = 2 [(gogoproto.jsontag) = "status" ]; string message = 3 [(gogoproto.jsontag) = "message" ]; + string nginx_id = 4 [(gogoproto.jsontag) = "nginx_id" ]; enum Status { PENDING = 0; diff --git a/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/events/event.pb.go b/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/events/event.pb.go index 0d8ac2fec..903408281 100644 --- a/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/events/event.pb.go +++ b/test/performance/vendor/github.com/nginx/agent/sdk/v2/proto/events/event.pb.go @@ -123,6 +123,7 @@ func (m *Metadata) GetCategory() string { type Event struct { Metadata *Metadata `protobuf:"bytes,1,opt,name=Metadata,proto3" json:"metadata"` // Types that are valid to be assigned to Data: + // // *Event_ActivityEvent // *Event_SecurityViolationEvent Data isEvent_Data `protobuf_oneof:"data"` diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go index 048b1be87..fe6346543 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/agent_api.go @@ -53,12 +53,12 @@ type AgentAPI struct { } type NginxHandler struct { - config *config.Config - env core.Environment - pipeline core.MessagePipeInterface - nginxBinary core.NginxBinary - responseChannel chan *proto.Command_NginxConfigResponse - configResponseStatus *proto.NginxConfigStatus + config *config.Config + env core.Environment + pipeline core.MessagePipeInterface + nginxBinary core.NginxBinary + responseChannel chan *proto.Command_NginxConfigResponse + configResponseStatuses map[string]*proto.NginxConfigStatus } type AgentAPIConfigApplyRequest struct { @@ -136,7 +136,9 @@ func (a *AgentAPI) Process(message *core.Message) { case core.NginxConfigValidationPending, core.NginxConfigApplyFailed, core.NginxConfigApplySucceeded: switch response := message.Data().(type) { case *proto.AgentActivityStatus: - a.nginxHandler.configResponseStatus = response.GetNginxConfigStatus() + log.Error(response) + nginxConfigStatus := response.GetNginxConfigStatus() + a.nginxHandler.configResponseStatuses[nginxConfigStatus.GetNginxId()] = nginxConfigStatus default: log.Errorf("Expected the type %T but got %T", &proto.AgentActivityStatus{}, response) } @@ -158,12 +160,12 @@ func (a *AgentAPI) Subscriptions() []string { func (a *AgentAPI) createHttpServer() { a.nginxHandler = &NginxHandler{ - config: a.config, - pipeline: a.pipeline, - env: a.env, - nginxBinary: a.nginxBinary, - responseChannel: make(chan *proto.Command_NginxConfigResponse), - configResponseStatus: &proto.NginxConfigStatus{}, + config: a.config, + pipeline: a.pipeline, + env: a.env, + nginxBinary: a.nginxBinary, + responseChannel: make(chan *proto.Command_NginxConfigResponse), + configResponseStatuses: make(map[string]*proto.NginxConfigStatus), } mux := http.NewServeMux() @@ -424,7 +426,23 @@ func (h *NginxHandler) getConfigStatus(w http.ResponseWriter, r *http.Request) e return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) } - if h.configResponseStatus.GetCorrelationId() != correlationId { + agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyResponse{ + CorrelationId: correlationId, + NginxInstances: []NginxInstanceResponse{}, + } + + for _, nginxConfigStatus := range h.configResponseStatuses { + if nginxConfigStatus.GetCorrelationId() == correlationId { + nginxInstanceResponse := NginxInstanceResponse{ + NginxId: nginxConfigStatus.GetNginxId(), + Message: nginxConfigStatus.GetMessage(), + Status: nginxConfigStatus.GetStatus().String(), + } + agentAPIConfigApplyStatusResponse.NginxInstances = append(agentAPIConfigApplyStatusResponse.NginxInstances, nginxInstanceResponse) + } + } + + if len(agentAPIConfigApplyStatusResponse.NginxInstances) == 0 { w.WriteHeader(http.StatusNotFound) agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ CorrelationId: correlationId, @@ -436,13 +454,6 @@ func (h *NginxHandler) getConfigStatus(w http.ResponseWriter, r *http.Request) e } w.WriteHeader(http.StatusOK) - - agentAPIConfigApplyStatusResponse := AgentAPIConfigApplyStatusResponse{ - CorrelationId: correlationId, - Message: h.configResponseStatus.Message, - Status: h.configResponseStatus.Status.String(), - } - return writeObjectToResponseBody(w, agentAPIConfigApplyStatusResponse) } diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/dataplane_status.go b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/dataplane_status.go index 255ff91c8..dc6a433f2 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/dataplane_status.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/dataplane_status.go @@ -23,25 +23,25 @@ import ( ) type DataPlaneStatus struct { - messagePipeline core.MessagePipeInterface - ctx context.Context - sendStatus chan bool - healthTicker *time.Ticker - interval time.Duration - meta *proto.Metadata - binary core.NginxBinary - env core.Environment - version string - tags *[]string - configDirs string - lastSendDetails time.Time - envHostInfo *proto.HostInfo - statusUrls map[string]string - reportInterval time.Duration - napDetails *proto.DataplaneSoftwareDetails_AppProtectWafDetails - agentActivityStatuses []*proto.AgentActivityStatus - napDetailsMutex sync.RWMutex - napHealth *proto.DataplaneSoftwareHealth_AppProtectWafHealth + messagePipeline core.MessagePipeInterface + ctx context.Context + sendStatus chan bool + healthTicker *time.Ticker + interval time.Duration + meta *proto.Metadata + binary core.NginxBinary + env core.Environment + version string + tags *[]string + configDirs string + lastSendDetails time.Time + envHostInfo *proto.HostInfo + statusUrls map[string]string + reportInterval time.Duration + napDetails *proto.DataplaneSoftwareDetails_AppProtectWafDetails + nginxConfigActivityStatuses map[string]*proto.AgentActivityStatus + napDetailsMutex sync.RWMutex + napHealth *proto.DataplaneSoftwareHealth_AppProtectWafHealth } const ( @@ -56,18 +56,19 @@ func NewDataPlaneStatus(config *config.Config, meta *proto.Metadata, binary core log.Warnf("interval set to %s, provided value (%s) less than minimum", pollInt, config.Dataplane.Status.PollInterval) } return &DataPlaneStatus{ - sendStatus: make(chan bool), - healthTicker: time.NewTicker(pollInt), - interval: pollInt, - meta: meta, - binary: binary, - env: env, - version: version, - tags: &config.Tags, - configDirs: config.ConfigDirs, - statusUrls: make(map[string]string), - reportInterval: config.Dataplane.Status.ReportInterval, - napDetailsMutex: sync.RWMutex{}, + sendStatus: make(chan bool), + healthTicker: time.NewTicker(pollInt), + interval: pollInt, + meta: meta, + binary: binary, + env: env, + version: version, + tags: &config.Tags, + configDirs: config.ConfigDirs, + statusUrls: make(map[string]string), + reportInterval: config.Dataplane.Status.ReportInterval, + napDetailsMutex: sync.RWMutex{}, + nginxConfigActivityStatuses: make(map[string]*proto.AgentActivityStatus), // Intentionally empty as it will be set later napDetails: nil, napHealth: &proto.DataplaneSoftwareHealth_AppProtectWafHealth{}, @@ -112,7 +113,7 @@ func (dps *DataPlaneStatus) Process(msg *core.Message) { log.Tracef("DataplaneStatus: %T message from topic %s received", msg.Data(), msg.Topic()) switch data := msg.Data().(type) { case *proto.AgentActivityStatus: - dps.updateAgentActivityStatuses(data) + dps.updateNginxConfigActivityStatuses(data) default: log.Errorf("Expected the type %T but got %T", &proto.AgentActivityStatus{}, data) } @@ -121,9 +122,8 @@ func (dps *DataPlaneStatus) Process(msg *core.Message) { log.Tracef("DataplaneStatus: %T message from topic %s received", msg.Data(), msg.Topic()) switch data := msg.Data().(type) { case *proto.AgentActivityStatus: - dps.updateAgentActivityStatuses(data) + dps.updateNginxConfigActivityStatuses(data) dps.sendDataplaneStatus(dps.messagePipeline, false) - dps.removeAgentActivityStatus(data) default: log.Errorf("Expected the type %T but got %T", &proto.AgentActivityStatus{}, data) } @@ -140,34 +140,10 @@ func (dps *DataPlaneStatus) Subscriptions() []string { } } -func (dps *DataPlaneStatus) updateAgentActivityStatuses(newAgentActivityStatus *proto.AgentActivityStatus) { - log.Tracef("DataplaneStatus: Adding %v to agentActivityStatuses", newAgentActivityStatus) +func (dps *DataPlaneStatus) updateNginxConfigActivityStatuses(newAgentActivityStatus *proto.AgentActivityStatus) { + log.Tracef("DataplaneStatus: Updating nginxConfigActivityStatuses with %v", newAgentActivityStatus) if _, ok := newAgentActivityStatus.GetStatus().(*proto.AgentActivityStatus_NginxConfigStatus); ok { - foundExistingNginxStatus := false - for index, agentActivityStatus := range dps.agentActivityStatuses { - if _, ok := agentActivityStatus.GetStatus().(*proto.AgentActivityStatus_NginxConfigStatus); ok { - dps.agentActivityStatuses[index] = newAgentActivityStatus - log.Tracef("DataplaneStatus: Updated agentActivityStatus with new status %v", newAgentActivityStatus) - foundExistingNginxStatus = true - } - } - - if !foundExistingNginxStatus { - dps.agentActivityStatuses = append(dps.agentActivityStatuses, newAgentActivityStatus) - log.Tracef("DataplaneStatus: Added new status %v to agentActivityStatus", newAgentActivityStatus) - } - } -} - -func (dps *DataPlaneStatus) removeAgentActivityStatus(agentActivityStatus *proto.AgentActivityStatus) { - log.Tracef("DataplaneStatus: Removing %v from agentActivityStatuses", agentActivityStatus) - if _, ok := agentActivityStatus.GetStatus().(*proto.AgentActivityStatus_NginxConfigStatus); ok { - for index, agentActivityStatus := range dps.agentActivityStatuses { - if _, ok := agentActivityStatus.GetStatus().(*proto.AgentActivityStatus_NginxConfigStatus); ok { - dps.agentActivityStatuses = append(dps.agentActivityStatuses[:index], dps.agentActivityStatuses[index+1:]...) - log.Tracef("DataplaneStatus: Removed %v from agentActivityStatus", agentActivityStatus) - } - } + dps.nginxConfigActivityStatuses[newAgentActivityStatus.GetNginxConfigStatus().GetNginxId()] = newAgentActivityStatus } } @@ -205,12 +181,18 @@ func (dps *DataPlaneStatus) dataplaneStatus(forceDetails bool) *proto.DataplaneS processes := dps.env.Processes() log.Tracef("dataplaneStatus: processes %v", processes) forceDetails = forceDetails || time.Now().UTC().Add(-dps.reportInterval).After(dps.lastSendDetails) + + agentActivityStatuses := []*proto.AgentActivityStatus{} + for _, nginxConfigActivityStatus := range dps.nginxConfigActivityStatuses { + agentActivityStatuses = append(agentActivityStatuses, nginxConfigActivityStatus) + } + return &proto.DataplaneStatus{ Host: dps.hostInfo(forceDetails), Details: dps.detailsForProcess(processes, forceDetails), Healths: dps.healthForProcess(processes), DataplaneSoftwareDetails: dps.dataplaneSoftwareDetails(), - AgentActivityStatus: dps.agentActivityStatuses, + AgentActivityStatus: agentActivityStatuses, } } diff --git a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go index 86cb600d5..a111b4019 100644 --- a/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go +++ b/test/performance/vendor/github.com/nginx/agent/v2/src/plugins/nginx.go @@ -326,6 +326,7 @@ func (n *Nginx) writeConfigAndReloadNginx(correlationId string, config *proto.Ng CorrelationId: correlationId, Status: proto.NginxConfigStatus_PENDING, Message: "config apply pending", + NginxId: config.GetConfigData().GetNginxId(), }, }, })) @@ -521,6 +522,7 @@ func (n *Nginx) completeConfigApply(response *NginxConfigValidationResponse) *pr CorrelationId: response.correlationId, Status: proto.NginxConfigStatus_OK, Message: nginxConfigStatusMessage, + NginxId: response.config.GetConfigData().GetNginxId(), }, }, } @@ -574,6 +576,7 @@ func (n *Nginx) rollbackConfigApply(response *NginxConfigValidationResponse) { CorrelationId: response.correlationId, Status: proto.NginxConfigStatus_ERROR, Message: nginxConfigStatusMessage, + NginxId: response.config.GetConfigData().GetNginxId(), }, }, } diff --git a/vendor/github.com/nginx/agent/sdk/v2/proto/command.pb.go b/vendor/github.com/nginx/agent/sdk/v2/proto/command.pb.go index 9cd0046a2..1eb5da172 100644 --- a/vendor/github.com/nginx/agent/sdk/v2/proto/command.pb.go +++ b/vendor/github.com/nginx/agent/sdk/v2/proto/command.pb.go @@ -631,6 +631,7 @@ type NginxConfigStatus struct { CorrelationId string `protobuf:"bytes,1,opt,name=correlation_id,json=correlationId,proto3" json:"correlation_id"` Status NginxConfigStatus_Status `protobuf:"varint,2,opt,name=status,proto3,enum=f5.nginx.agent.sdk.NginxConfigStatus_Status" json:"status"` Message string `protobuf:"bytes,3,opt,name=message,proto3" json:"message"` + NginxId string `protobuf:"bytes,4,opt,name=nginx_id,json=nginxId,proto3" json:"nginx_id"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -690,6 +691,13 @@ func (m *NginxConfigStatus) GetMessage() string { return "" } +func (m *NginxConfigStatus) GetNginxId() string { + if m != nil { + return m.NginxId + } + return "" +} + type DataplaneSoftwareHealth struct { // Types that are valid to be assigned to Health: // *DataplaneSoftwareHealth_NginxHealth @@ -1253,103 +1261,103 @@ func init() { func init() { proto.RegisterFile("command.proto", fileDescriptor_213c0bb044472049) } var fileDescriptor_213c0bb044472049 = []byte{ - // 1521 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0x4d, 0x6f, 0xdb, 0xc6, - 0x16, 0x25, 0x15, 0xeb, 0xeb, 0x4a, 0xb6, 0x95, 0xb1, 0x93, 0x28, 0x46, 0x60, 0x1a, 0x7c, 0x2f, - 0x2f, 0xce, 0x7b, 0x79, 0x12, 0xea, 0xa0, 0x08, 0x9a, 0xac, 0x24, 0x4b, 0x09, 0x85, 0xc4, 0x92, - 0x31, 0x89, 0x13, 0x20, 0x45, 0x21, 0x30, 0xe2, 0x48, 0x16, 0x6c, 0x91, 0x2c, 0x49, 0x39, 0x71, - 0xd0, 0x7d, 0xd1, 0xa2, 0x9b, 0x2e, 0xba, 0x28, 0xfa, 0x23, 0xfa, 0x37, 0xba, 0xcc, 0xba, 0x0b, - 0xa2, 0xc8, 0x92, 0xbb, 0x6e, 0xda, 0x45, 0x37, 0xc5, 0x7c, 0x50, 0xa2, 0x24, 0x4a, 0x76, 0xea, - 0xa2, 0x1b, 0xce, 0x70, 0x78, 0xee, 0xb9, 0x77, 0xee, 0xcc, 0x9c, 0xb9, 0x12, 0x2c, 0x77, 0xac, - 0xc1, 0x40, 0x37, 0x8d, 0x92, 0xed, 0x58, 0x9e, 0x85, 0x50, 0xf7, 0xe3, 0x92, 0xd9, 0xeb, 0x9b, - 0x6f, 0x4a, 0x7a, 0x8f, 0x98, 0x5e, 0xc9, 0x35, 0x8e, 0x36, 0xa0, 0x67, 0xf5, 0x2c, 0xfe, 0x7d, - 0x23, 0x4f, 0xe1, 0x96, 0x29, 0xde, 0x72, 0x1c, 0xc4, 0x5f, 0xe0, 0xd0, 0x72, 0xc3, 0x7e, 0x8e, - 0x73, 0x8c, 0x6c, 0xcc, 0x6e, 0xbf, 0x27, 0xde, 0x10, 0x39, 0x21, 0xa6, 0xe7, 0x96, 0x59, 0x23, - 0xc6, 0xae, 0x1b, 0x76, 0xdb, 0xb5, 0xba, 0xde, 0x6b, 0xdd, 0x21, 0x6d, 0x83, 0x78, 0x7a, 0xff, - 0xd8, 0x15, 0x9f, 0xb2, 0xa6, 0x6e, 0xf3, 0xae, 0xfa, 0x07, 0x40, 0x7a, 0x97, 0x47, 0x8b, 0xee, - 0xc3, 0xd2, 0x80, 0x78, 0x7a, 0x51, 0xde, 0x92, 0xb7, 0x73, 0x3b, 0x37, 0x4a, 0xb3, 0x61, 0x97, - 0xf6, 0x88, 0xa7, 0x1b, 0xba, 0xa7, 0x57, 0x33, 0x81, 0xaf, 0x30, 0x34, 0x66, 0x4f, 0x54, 0x87, - 0x25, 0xef, 0xd4, 0x26, 0xc5, 0xc4, 0x96, 0xbc, 0xbd, 0xb2, 0x73, 0x2b, 0xce, 0x56, 0xb8, 0x09, - 0xdb, 0x67, 0xa7, 0x36, 0xe1, 0x34, 0xd4, 0x10, 0xb3, 0x27, 0x7a, 0x09, 0xd0, 0x19, 0x18, 0x6d, - 0xd7, 0xd3, 0xbd, 0xa1, 0x5b, 0xbc, 0xc4, 0x02, 0xb9, 0xbd, 0x80, 0xec, 0x29, 0x03, 0x62, 0xe2, - 0xda, 0x96, 0xe9, 0x92, 0xea, 0x4a, 0xe0, 0x2b, 0x11, 0x02, 0x4d, 0xc2, 0xd9, 0xce, 0x40, 0x80, - 0xd0, 0x73, 0xc8, 0x33, 0x96, 0x36, 0x4f, 0x5d, 0x71, 0x89, 0xb1, 0x2b, 0x71, 0xec, 0x4d, 0xfa, - 0xbe, 0xcb, 0x60, 0xd5, 0x42, 0xe0, 0x2b, 0x13, 0x86, 0x9a, 0x84, 0xf9, 0x52, 0x70, 0x00, 0x7a, - 0x03, 0x57, 0xa2, 0x9f, 0xdb, 0x8e, 0x88, 0xa6, 0x98, 0x64, 0x0e, 0x6e, 0x9d, 0xe1, 0x60, 0x14, - 0xfc, 0xf5, 0xc0, 0x57, 0xe2, 0x99, 0x34, 0x09, 0xaf, 0x99, 0xb3, 0x16, 0xd4, 0x33, 0xa3, 0xa4, - 0x78, 0x93, 0x74, 0xbc, 0xb6, 0x43, 0x3e, 0x1f, 0x12, 0xd7, 0x2b, 0xa6, 0xe6, 0x7b, 0xae, 0xd0, - 0xde, 0x2e, 0xc7, 0x63, 0x0e, 0xe7, 0x9e, 0x63, 0x99, 0xa8, 0x67, 0x7d, 0xd6, 0x02, 0x7d, 0x01, - 0x57, 0xa7, 0xf1, 0x62, 0xd2, 0x69, 0xe6, 0x7a, 0xfb, 0x6c, 0xd7, 0x62, 0xd6, 0x1b, 0x81, 0xaf, - 0xcc, 0xe1, 0xd2, 0x24, 0xbc, 0xae, 0xc7, 0xd8, 0x20, 0x0f, 0xd6, 0x47, 0x16, 0x3c, 0x4f, 0x7c, - 0xda, 0x19, 0xe6, 0xfb, 0x3f, 0x8b, 0x7c, 0xb3, 0xf4, 0xf1, 0x59, 0x17, 0x03, 0x5f, 0x89, 0xe5, - 0xd1, 0x24, 0x8c, 0xf4, 0x19, 0x3c, 0xdd, 0x3f, 0x51, 0x74, 0x31, 0x3b, 0x7f, 0xff, 0x44, 0xbc, - 0xf1, 0xfd, 0x13, 0x35, 0xa4, 0xfb, 0x27, 0x42, 0x8f, 0xba, 0x50, 0xa0, 0x47, 0xca, 0x3e, 0xd6, - 0x4d, 0x12, 0xee, 0xfc, 0x1c, 0xe3, 0xfe, 0x57, 0x1c, 0x77, 0x2d, 0xc4, 0xf2, 0x6d, 0x5d, 0x5d, - 0x0f, 0x7c, 0x65, 0x86, 0x40, 0x93, 0xf0, 0xaa, 0x31, 0x09, 0x44, 0x9f, 0x41, 0x9e, 0xe9, 0x43, - 0xdb, 0x21, 0xb6, 0xe5, 0x78, 0xc5, 0xfc, 0xfc, 0x6c, 0x71, 0x39, 0x29, 0xd5, 0x69, 0x83, 0x19, - 0x9a, 0x4f, 0x23, 0x6a, 0x4f, 0xa7, 0x41, 0xc6, 0x00, 0xf4, 0x8d, 0x0c, 0x1b, 0x91, 0x30, 0xa6, - 0x94, 0xa7, 0xb8, 0xcc, 0xbc, 0xdd, 0x59, 0x3c, 0x23, 0x61, 0x54, 0xe3, 0x36, 0xd5, 0xcd, 0xc0, - 0x57, 0x16, 0x70, 0x6a, 0x12, 0x2e, 0x1a, 0x73, 0x6c, 0x27, 0xb3, 0x3a, 0xb4, 0x0d, 0xdd, 0x23, - 0xc5, 0x95, 0x73, 0x64, 0xf5, 0x80, 0x41, 0xa7, 0xb3, 0xca, 0x09, 0x26, 0xb2, 0xca, 0x81, 0xea, - 0x5d, 0xc8, 0x45, 0x04, 0x0d, 0x01, 0xa4, 0x9a, 0x2d, 0xbc, 0x57, 0x79, 0x52, 0x90, 0x50, 0x1e, - 0x32, 0xb5, 0xd6, 0x8b, 0xe6, 0x93, 0x56, 0xa5, 0x56, 0x90, 0xe9, 0x97, 0x83, 0x7d, 0xd6, 0x4f, - 0x54, 0x53, 0xb0, 0x44, 0x79, 0xd4, 0xef, 0x2e, 0xc1, 0x95, 0x58, 0x25, 0x43, 0x9f, 0x42, 0x4a, - 0x6c, 0x05, 0x99, 0x29, 0xea, 0xbd, 0x73, 0x8b, 0xe0, 0xe4, 0x68, 0x15, 0x02, 0x5f, 0x11, 0x54, - 0x58, 0xb4, 0xa8, 0x0f, 0x40, 0x1c, 0xc7, 0x72, 0xda, 0x1d, 0xcb, 0x08, 0x25, 0xfb, 0xfe, 0x07, - 0x3b, 0xa8, 0x53, 0x8a, 0x5d, 0xcb, 0x10, 0xb2, 0x3b, 0x66, 0xc4, 0x59, 0x12, 0x7e, 0x42, 0x37, - 0x21, 0x3d, 0x20, 0xae, 0xab, 0xf7, 0x08, 0x53, 0xf3, 0x6c, 0x35, 0x17, 0xf8, 0x4a, 0x38, 0x84, - 0xc3, 0x0e, 0x52, 0x20, 0xc9, 0x6c, 0x98, 0x28, 0x67, 0xab, 0xd9, 0xc0, 0x57, 0xf8, 0x00, 0xe6, - 0x8d, 0xfa, 0x00, 0x96, 0x27, 0x82, 0x41, 0xab, 0x90, 0xdb, 0xdd, 0xab, 0xb5, 0x0f, 0x9a, 0x8f, - 0x9b, 0xad, 0x17, 0xcd, 0x82, 0x44, 0xf3, 0x4b, 0x07, 0x5a, 0x8f, 0x0b, 0x32, 0x5a, 0x86, 0x2c, - 0xed, 0xd7, 0x31, 0x6e, 0xe1, 0x42, 0x42, 0x2d, 0x43, 0x61, 0x3a, 0x66, 0x0a, 0xaf, 0x63, 0x4c, - 0xe1, 0x12, 0xe5, 0xa2, 0xfd, 0x90, 0x4b, 0x56, 0x7f, 0x48, 0xc2, 0xea, 0xd4, 0x39, 0x43, 0xff, - 0x85, 0xac, 0x7b, 0xea, 0x7a, 0x64, 0xd0, 0xee, 0x1b, 0x6c, 0x51, 0xb2, 0xd5, 0xe5, 0xc0, 0x57, - 0xc6, 0x83, 0x38, 0xc3, 0xbb, 0x0d, 0x03, 0x3d, 0x82, 0x74, 0xb8, 0xef, 0x13, 0x5b, 0x97, 0xb6, - 0x73, 0x3b, 0x5b, 0x73, 0x2f, 0x81, 0x70, 0xaf, 0xb3, 0xbc, 0x08, 0x23, 0x1c, 0x76, 0xe8, 0x95, - 0x4c, 0x2b, 0x00, 0x71, 0x13, 0xc6, 0x5e, 0xc9, 0x9a, 0xe5, 0x7a, 0x0d, 0xb3, 0x6b, 0xf1, 0xbb, - 0x94, 0xa2, 0x31, 0x7b, 0xa2, 0x87, 0x90, 0x3e, 0x24, 0xfa, 0xb1, 0x77, 0xe8, 0x16, 0x93, 0x2c, - 0x88, 0xf9, 0x57, 0x9d, 0xc6, 0x70, 0x3c, 0x06, 0x61, 0x83, 0xc3, 0x0e, 0xfa, 0x7a, 0xf1, 0xc1, - 0x4e, 0x31, 0xee, 0xbf, 0xf5, 0x60, 0x2f, 0x38, 0xd6, 0x5f, 0xc5, 0x07, 0x13, 0x4e, 0x34, 0xcd, - 0x82, 0xf9, 0xdf, 0xb9, 0x82, 0x11, 0x93, 0x9e, 0x17, 0x4b, 0x98, 0x87, 0xd9, 0x58, 0x34, 0x91, - 0x98, 0x93, 0xf0, 0xfa, 0xd5, 0x3b, 0x5e, 0xff, 0xa4, 0xef, 0x9d, 0x86, 0xea, 0x9d, 0x61, 0x51, - 0xcc, 0xbf, 0x7e, 0x2b, 0x02, 0x2f, 0x8e, 0x68, 0xe4, 0xfa, 0x9d, 0x62, 0x12, 0x97, 0xef, 0x24, - 0x5e, 0xfd, 0x56, 0x86, 0xb5, 0x18, 0x1e, 0x64, 0xc3, 0xda, 0x44, 0xf9, 0x10, 0x11, 0x90, 0xdc, - 0xce, 0xcd, 0x33, 0xca, 0x10, 0x11, 0xcb, 0xb5, 0xc0, 0x57, 0xe2, 0x58, 0x34, 0x09, 0x5f, 0x36, - 0x67, 0xd0, 0x19, 0x48, 0x89, 0x98, 0x7e, 0x95, 0xe1, 0xf2, 0x0c, 0x1b, 0xfa, 0x04, 0x56, 0x3a, - 0x96, 0xe3, 0x90, 0x63, 0xdd, 0xeb, 0x5b, 0xe6, 0xf8, 0xe0, 0xa0, 0xc0, 0x57, 0xa6, 0xbe, 0xe0, - 0xe5, 0xc8, 0x7b, 0xc3, 0x40, 0xfb, 0x23, 0x01, 0xe4, 0xfa, 0x74, 0xe7, 0x5c, 0xf1, 0x97, 0x16, - 0xa8, 0xde, 0xf9, 0xa4, 0x48, 0xdd, 0x0e, 0xe7, 0x84, 0x72, 0x90, 0xde, 0xaf, 0x37, 0x6b, 0x8d, - 0xe6, 0xa3, 0x82, 0x84, 0x52, 0x90, 0x60, 0xd2, 0x92, 0x85, 0x64, 0x28, 0x2b, 0xbf, 0xcb, 0x70, - 0x6d, 0xce, 0xae, 0x1a, 0x17, 0x9b, 0x7c, 0x1b, 0x89, 0x45, 0x38, 0xf3, 0x04, 0x46, 0x8a, 0x4d, - 0x6e, 0x38, 0x2a, 0x36, 0x05, 0xef, 0x5b, 0xb8, 0xaa, 0xdb, 0x76, 0x9b, 0x16, 0xef, 0xb4, 0x54, - 0x7a, 0xad, 0x77, 0x43, 0x0f, 0x89, 0x05, 0x35, 0x9f, 0x6d, 0xef, 0x73, 0x83, 0x17, 0x95, 0x87, - 0xc2, 0x13, 0xaf, 0xbb, 0x62, 0xa9, 0x58, 0xd1, 0x37, 0x36, 0xd1, 0xbb, 0xc2, 0x24, 0x03, 0x29, - 0x0e, 0x50, 0x7f, 0x96, 0x23, 0xfa, 0xc8, 0x2f, 0xc2, 0x91, 0x54, 0xc9, 0x7f, 0x41, 0xaa, 0xce, - 0x90, 0x98, 0xc4, 0x3f, 0x29, 0x31, 0xea, 0x1e, 0xac, 0xd6, 0xac, 0xd7, 0xe6, 0xb1, 0xa5, 0x1b, - 0x61, 0xe9, 0x77, 0x81, 0x5f, 0x46, 0xea, 0x97, 0x09, 0x58, 0x8b, 0x29, 0xf7, 0xd1, 0xde, 0xc4, - 0x0d, 0xff, 0x41, 0x3f, 0x73, 0xe2, 0x76, 0x77, 0x03, 0x52, 0x54, 0x3c, 0x2c, 0x53, 0x9c, 0x97, - 0xb3, 0xce, 0x7b, 0x85, 0x81, 0x39, 0x15, 0x37, 0xc4, 0xa2, 0x45, 0xcf, 0x21, 0x27, 0xce, 0x3e, - 0x9d, 0x90, 0xb8, 0x7b, 0xfe, 0x1d, 0x1f, 0x1e, 0x85, 0xd5, 0x88, 0xdb, 0x71, 0xfa, 0xb6, 0x67, - 0x39, 0xd5, 0xd5, 0xc0, 0x57, 0xa2, 0xc6, 0x18, 0xf8, 0x0b, 0x5d, 0x26, 0xf5, 0x37, 0x19, 0xf2, - 0x07, 0x36, 0xcd, 0xab, 0x38, 0x60, 0x17, 0xf9, 0xc1, 0xf9, 0x74, 0x4a, 0x1f, 0xca, 0x71, 0xd6, - 0x51, 0x6f, 0xa5, 0x67, 0x8e, 0x6e, 0xba, 0x5d, 0xe2, 0x2c, 0x90, 0x08, 0x15, 0x52, 0x0e, 0xd1, - 0x5d, 0xcb, 0x14, 0x0a, 0xc1, 0x30, 0x7c, 0x04, 0x8b, 0x56, 0xfd, 0x08, 0x56, 0x26, 0x99, 0xa8, - 0x4e, 0x8c, 0xcb, 0x90, 0x50, 0x27, 0x00, 0x52, 0x0f, 0x2b, 0x8d, 0x27, 0xf5, 0x5a, 0x21, 0xa1, - 0xfe, 0x28, 0x43, 0x96, 0x66, 0x60, 0xf7, 0x70, 0x68, 0x1e, 0xa1, 0x16, 0x3b, 0x46, 0x06, 0x71, - 0x16, 0x2e, 0x3c, 0x85, 0x12, 0x03, 0x13, 0xd7, 0x1a, 0x3a, 0x1d, 0xaa, 0x2a, 0x06, 0x71, 0x78, - 0x3c, 0xdc, 0x58, 0x93, 0xb0, 0xe8, 0x21, 0x8d, 0x57, 0x93, 0x42, 0x01, 0xb6, 0xcf, 0x41, 0xc7, - 0x5e, 0x79, 0x4a, 0xa9, 0xa5, 0x26, 0x61, 0xd6, 0x56, 0xd3, 0x90, 0xec, 0xd0, 0x4f, 0xea, 0x3b, - 0x19, 0xae, 0xc4, 0x86, 0x70, 0xa1, 0x35, 0x53, 0x21, 0xc5, 0xe8, 0xf9, 0x9a, 0x25, 0xf9, 0x74, - 0xf8, 0x08, 0x16, 0x2d, 0xda, 0x86, 0x4c, 0xe7, 0x90, 0x74, 0x8e, 0xdc, 0xe1, 0x40, 0x2c, 0x42, - 0x3e, 0xf0, 0x95, 0xd1, 0x18, 0x1e, 0xf5, 0xd0, 0xff, 0x01, 0x98, 0x4d, 0xdb, 0xed, 0xbf, 0x25, - 0xac, 0x70, 0x4c, 0x8a, 0x3f, 0x00, 0x46, 0xa3, 0x38, 0xcb, 0xfa, 0x4f, 0xfb, 0x6f, 0x89, 0xfa, - 0xbd, 0x0c, 0xeb, 0x71, 0x69, 0xb8, 0xd0, 0x8c, 0x6e, 0xd1, 0x68, 0xa9, 0xb7, 0xbe, 0x21, 0xe6, - 0x24, 0xa2, 0xe5, 0x63, 0x38, 0xcd, 0x7a, 0x0d, 0x03, 0xdd, 0x10, 0x6b, 0x44, 0xa7, 0x94, 0x1f, - 0x67, 0x5e, 0xe4, 0xfd, 0xde, 0x4f, 0xef, 0x37, 0xe5, 0x77, 0xef, 0x37, 0xe5, 0x5f, 0xde, 0x6f, - 0xca, 0x2f, 0x6f, 0xf7, 0xfa, 0xde, 0xe1, 0xf0, 0x55, 0xa9, 0x63, 0x0d, 0xca, 0x2c, 0x92, 0x32, - 0x8b, 0xa4, 0xec, 0x1a, 0x47, 0xe5, 0x93, 0x9d, 0x32, 0xfb, 0xe3, 0xe6, 0x01, 0x7b, 0xbe, 0x4a, - 0xb1, 0xe6, 0xee, 0x9f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc3, 0xee, 0xd6, 0x35, 0x72, 0x12, 0x00, - 0x00, + // 1535 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x58, 0xcb, 0x6e, 0xdb, 0x46, + 0x17, 0x26, 0x15, 0xeb, 0x76, 0x24, 0xdb, 0xca, 0xd8, 0x49, 0x14, 0x23, 0x30, 0x0d, 0xfe, 0x7f, + 0x6a, 0xa7, 0x4d, 0x25, 0xd4, 0x41, 0x11, 0x34, 0x59, 0x59, 0x96, 0x13, 0x0a, 0x89, 0x65, 0x63, + 0x12, 0x27, 0x40, 0x8a, 0x42, 0x60, 0xc4, 0x91, 0x4c, 0xd8, 0x22, 0x59, 0x92, 0x72, 0xe2, 0xa0, + 0xfb, 0xa2, 0x45, 0x37, 0x5d, 0x74, 0xd1, 0xf6, 0x21, 0xfa, 0x1a, 0x5d, 0x66, 0xdd, 0x05, 0x51, + 0x64, 0xc9, 0x07, 0x68, 0x17, 0xdd, 0x14, 0x73, 0xa1, 0x44, 0x49, 0x94, 0xec, 0xd4, 0x45, 0x37, + 0x9a, 0xe1, 0xf0, 0x3b, 0xdf, 0xb9, 0xcc, 0xcc, 0x37, 0x43, 0xc1, 0x7c, 0xdb, 0xee, 0xf5, 0x74, + 0xcb, 0xa8, 0x38, 0xae, 0xed, 0xdb, 0x08, 0x75, 0x3e, 0xad, 0x58, 0x5d, 0xd3, 0x7a, 0x5d, 0xd1, + 0xbb, 0xc4, 0xf2, 0x2b, 0x9e, 0x71, 0xb4, 0x02, 0x5d, 0xbb, 0x6b, 0xf3, 0xf7, 0x2b, 0x45, 0x0a, + 0xb7, 0x2d, 0xf1, 0x54, 0xe0, 0x20, 0xfe, 0x00, 0x87, 0xb6, 0x17, 0xf5, 0x0b, 0x9c, 0x63, 0x60, + 0x63, 0x75, 0xcc, 0xae, 0x78, 0x42, 0xe4, 0x84, 0x58, 0xbe, 0x57, 0x65, 0x8d, 0x18, 0xbb, 0x6e, + 0x38, 0x2d, 0xcf, 0xee, 0xf8, 0xaf, 0x74, 0x97, 0xb4, 0x0c, 0xe2, 0xeb, 0xe6, 0xb1, 0x27, 0x5e, + 0xe5, 0x2d, 0xdd, 0xe1, 0x5d, 0xf5, 0x2f, 0x80, 0xec, 0x36, 0x8f, 0x16, 0xdd, 0x83, 0xb9, 0x1e, + 0xf1, 0xf5, 0xb2, 0xbc, 0x26, 0x6f, 0x14, 0x36, 0x6f, 0x54, 0x26, 0xc3, 0xae, 0xec, 0x12, 0x5f, + 0x37, 0x74, 0x5f, 0xaf, 0xe5, 0xc2, 0x40, 0x61, 0x68, 0xcc, 0x7e, 0xd1, 0x0e, 0xcc, 0xf9, 0xa7, + 0x0e, 0x29, 0xa7, 0xd6, 0xe4, 0x8d, 0x85, 0xcd, 0xf5, 0x24, 0x5b, 0xe1, 0x26, 0x6a, 0x9f, 0x9e, + 0x3a, 0x84, 0xd3, 0x50, 0x43, 0xcc, 0x7e, 0xd1, 0x0b, 0x80, 0x76, 0xcf, 0x68, 0x79, 0xbe, 0xee, + 0xf7, 0xbd, 0xf2, 0x25, 0x16, 0xc8, 0xad, 0x19, 0x64, 0x4f, 0x18, 0x10, 0x13, 0xcf, 0xb1, 0x2d, + 0x8f, 0xd4, 0x16, 0xc2, 0x40, 0x89, 0x11, 0x68, 0x12, 0xce, 0xb7, 0x7b, 0x02, 0x84, 0x9e, 0x41, + 0x91, 0xb1, 0xb4, 0x78, 0xe9, 0xca, 0x73, 0x8c, 0x5d, 0x49, 0x62, 0x6f, 0xd2, 0xe7, 0x6d, 0x06, + 0xab, 0x95, 0xc2, 0x40, 0x19, 0x31, 0xd4, 0x24, 0xcc, 0xa7, 0x82, 0x03, 0xd0, 0x6b, 0xb8, 0x12, + 0x7f, 0xdd, 0x72, 0x45, 0x34, 0xe5, 0x34, 0x73, 0xb0, 0x7e, 0x86, 0x83, 0x41, 0xf0, 0xd7, 0xc3, + 0x40, 0x49, 0x66, 0xd2, 0x24, 0xbc, 0x64, 0x4d, 0x5a, 0x50, 0xcf, 0x8c, 0x92, 0xe2, 0x2d, 0xd2, + 0xf6, 0x5b, 0x2e, 0xf9, 0xb2, 0x4f, 0x3c, 0xbf, 0x9c, 0x99, 0xee, 0x79, 0x8b, 0xf6, 0xb6, 0x39, + 0x1e, 0x73, 0x38, 0xf7, 0x9c, 0xc8, 0x44, 0x3d, 0xeb, 0x93, 0x16, 0xe8, 0x2b, 0xb8, 0x3a, 0x8e, + 0x17, 0x49, 0x67, 0x99, 0xeb, 0x8d, 0xb3, 0x5d, 0x8b, 0xac, 0x57, 0xc2, 0x40, 0x99, 0xc2, 0xa5, + 0x49, 0x78, 0x59, 0x4f, 0xb0, 0x41, 0x3e, 0x2c, 0x0f, 0x2c, 0x78, 0x9d, 0x78, 0xda, 0x39, 0xe6, + 0xfb, 0x83, 0x59, 0xbe, 0x59, 0xf9, 0x78, 0xd6, 0xe5, 0x30, 0x50, 0x12, 0x79, 0x34, 0x09, 0x23, + 0x7d, 0x02, 0x4f, 0xd7, 0x4f, 0x1c, 0x5d, 0xce, 0x4f, 0x5f, 0x3f, 0x31, 0x6f, 0x7c, 0xfd, 0xc4, + 0x0d, 0xe9, 0xfa, 0x89, 0xd1, 0xa3, 0x0e, 0x94, 0xe8, 0x96, 0x72, 0x8e, 0x75, 0x8b, 0x44, 0x2b, + 0xbf, 0xc0, 0xb8, 0xff, 0x97, 0xc4, 0x5d, 0x8f, 0xb0, 0x7c, 0x59, 0xd7, 0x96, 0xc3, 0x40, 0x99, + 0x20, 0xd0, 0x24, 0xbc, 0x68, 0x8c, 0x02, 0xd1, 0x17, 0x50, 0x64, 0xfa, 0xd0, 0x72, 0x89, 0x63, + 0xbb, 0x7e, 0xb9, 0x38, 0xbd, 0x5a, 0x5c, 0x4e, 0x2a, 0x3b, 0xb4, 0xc1, 0x0c, 0xcd, 0xd3, 0x88, + 0xdb, 0xd3, 0x34, 0xc8, 0x10, 0x80, 0xbe, 0x93, 0x61, 0x25, 0x16, 0xc6, 0x98, 0xf2, 0x94, 0xe7, + 0x99, 0xb7, 0xdb, 0xb3, 0x33, 0x12, 0x46, 0x75, 0x6e, 0x53, 0x5b, 0x0d, 0x03, 0x65, 0x06, 0xa7, + 0x26, 0xe1, 0xb2, 0x31, 0xc5, 0x76, 0xb4, 0xaa, 0x7d, 0xc7, 0xd0, 0x7d, 0x52, 0x5e, 0x38, 0x47, + 0x55, 0x0f, 0x18, 0x74, 0xbc, 0xaa, 0x9c, 0x60, 0xa4, 0xaa, 0x1c, 0xa8, 0xde, 0x81, 0x42, 0x4c, + 0xd0, 0x10, 0x40, 0xa6, 0xb9, 0x87, 0x77, 0xb7, 0x1e, 0x97, 0x24, 0x54, 0x84, 0x5c, 0x7d, 0xef, + 0x79, 0xf3, 0xf1, 0xde, 0x56, 0xbd, 0x24, 0xd3, 0x37, 0x07, 0xfb, 0xac, 0x9f, 0xaa, 0x65, 0x60, + 0x8e, 0xf2, 0xa8, 0x3f, 0x5c, 0x82, 0x2b, 0x89, 0x4a, 0x86, 0x3e, 0x87, 0x8c, 0x58, 0x0a, 0x32, + 0x53, 0xd4, 0xbb, 0xe7, 0x16, 0xc1, 0xd1, 0xd1, 0x1a, 0x84, 0x81, 0x22, 0xa8, 0xb0, 0x68, 0x91, + 0x09, 0x40, 0x5c, 0xd7, 0x76, 0x5b, 0x6d, 0xdb, 0x88, 0x24, 0xfb, 0xde, 0x7b, 0x3b, 0xd8, 0xa1, + 0x14, 0xdb, 0xb6, 0x21, 0x64, 0x77, 0xc8, 0x88, 0xf3, 0x24, 0x7a, 0x85, 0x6e, 0x42, 0xb6, 0x47, + 0x3c, 0x4f, 0xef, 0x12, 0xa6, 0xe6, 0xf9, 0x5a, 0x21, 0x0c, 0x94, 0x68, 0x08, 0x47, 0x1d, 0xa4, + 0x40, 0x9a, 0xd9, 0x30, 0x51, 0xce, 0xd7, 0xf2, 0x61, 0xa0, 0xf0, 0x01, 0xcc, 0x1b, 0xf5, 0x3e, + 0xcc, 0x8f, 0x04, 0x83, 0x16, 0xa1, 0xb0, 0xbd, 0x5b, 0x6f, 0x1d, 0x34, 0x1f, 0x35, 0xf7, 0x9e, + 0x37, 0x4b, 0x12, 0xad, 0x2f, 0x1d, 0xd8, 0x7b, 0x54, 0x92, 0xd1, 0x3c, 0xe4, 0x69, 0x7f, 0x07, + 0xe3, 0x3d, 0x5c, 0x4a, 0xa9, 0x55, 0x28, 0x8d, 0xc7, 0x4c, 0xe1, 0x3b, 0x18, 0x53, 0xb8, 0x44, + 0xb9, 0x68, 0x3f, 0xe2, 0x92, 0xd5, 0x9f, 0xd3, 0xb0, 0x38, 0xb6, 0xcf, 0xd0, 0x87, 0x90, 0xf7, + 0x4e, 0x3d, 0x9f, 0xf4, 0x5a, 0xa6, 0xc1, 0x26, 0x25, 0x5f, 0x9b, 0x0f, 0x03, 0x65, 0x38, 0x88, + 0x73, 0xbc, 0xdb, 0x30, 0xd0, 0x43, 0xc8, 0x46, 0xeb, 0x3e, 0xb5, 0x76, 0x69, 0xa3, 0xb0, 0xb9, + 0x36, 0xf5, 0x10, 0x88, 0xd6, 0x3a, 0xab, 0x8b, 0x30, 0xc2, 0x51, 0x87, 0x1e, 0xc9, 0xf4, 0x06, + 0x20, 0x4e, 0xc2, 0xc4, 0x23, 0x59, 0xb3, 0x3d, 0xbf, 0x61, 0x75, 0x6c, 0x7e, 0x96, 0x52, 0x34, + 0x66, 0xbf, 0xe8, 0x01, 0x64, 0x0f, 0x89, 0x7e, 0xec, 0x1f, 0x7a, 0xe5, 0x34, 0x0b, 0x62, 0xfa, + 0x51, 0xa7, 0x31, 0x1c, 0x8f, 0x41, 0xd8, 0xe0, 0xa8, 0x83, 0xbe, 0x9d, 0xbd, 0xb1, 0x33, 0x8c, + 0xfb, 0x5f, 0xdd, 0xd8, 0x33, 0xb6, 0xf5, 0x37, 0xc9, 0xc1, 0x44, 0x89, 0x66, 0x59, 0x30, 0x1f, + 0x9d, 0x2b, 0x18, 0x91, 0xf4, 0xb4, 0x58, 0xa2, 0x3a, 0x4c, 0xc6, 0xa2, 0x89, 0xc2, 0x9c, 0x44, + 0xc7, 0xaf, 0xde, 0xf6, 0xcd, 0x13, 0xd3, 0x3f, 0x8d, 0xd4, 0x3b, 0xc7, 0xa2, 0x98, 0x7e, 0xfc, + 0x6e, 0x09, 0xbc, 0xd8, 0xa2, 0xb1, 0xe3, 0x77, 0x8c, 0x49, 0x1c, 0xbe, 0xa3, 0x78, 0xf5, 0x7b, + 0x19, 0x96, 0x12, 0x78, 0x90, 0x03, 0x4b, 0x23, 0xd7, 0x87, 0x98, 0x80, 0x14, 0x36, 0x6f, 0x9e, + 0x71, 0x0d, 0x11, 0xb1, 0x5c, 0x0b, 0x03, 0x25, 0x89, 0x45, 0x93, 0xf0, 0x65, 0x6b, 0x02, 0x9d, + 0x83, 0x8c, 0x88, 0xe9, 0xa7, 0x14, 0x5c, 0x9e, 0x60, 0x43, 0x9f, 0xc1, 0x42, 0xdb, 0x76, 0x5d, + 0x72, 0xac, 0xfb, 0xa6, 0x6d, 0x0d, 0x37, 0x0e, 0x0a, 0x03, 0x65, 0xec, 0x0d, 0x9e, 0x8f, 0x3d, + 0x37, 0x0c, 0xb4, 0x3f, 0x10, 0x40, 0xae, 0x4f, 0xb7, 0xcf, 0x15, 0x7f, 0x65, 0x86, 0xea, 0x9d, + 0x53, 0x8a, 0xd6, 0x21, 0xc7, 0xf3, 0x37, 0x0d, 0xa1, 0x46, 0xc5, 0x30, 0x50, 0x06, 0x63, 0x38, + 0xcb, 0x7a, 0x0d, 0x43, 0xdd, 0x88, 0x92, 0x47, 0x05, 0xc8, 0xee, 0xef, 0x34, 0xeb, 0x8d, 0xe6, + 0xc3, 0x92, 0x84, 0x32, 0x90, 0x62, 0x1a, 0x94, 0x87, 0x74, 0xa4, 0x3f, 0x7f, 0xca, 0x70, 0x6d, + 0xca, 0xf2, 0x1b, 0xde, 0x4a, 0xf9, 0x7a, 0x13, 0xb3, 0x75, 0xe6, 0x56, 0x8d, 0xdd, 0x4a, 0xb9, + 0xe1, 0xe0, 0x56, 0x2a, 0x78, 0xdf, 0xc0, 0x55, 0xdd, 0x71, 0x5a, 0xf4, 0x96, 0x4f, 0xef, 0x54, + 0xaf, 0xf4, 0x4e, 0xe4, 0x21, 0x35, 0xe3, 0x72, 0xe8, 0x38, 0xfb, 0xdc, 0xe0, 0xf9, 0xd6, 0x03, + 0xe1, 0x89, 0x5f, 0xd0, 0x12, 0xa9, 0xd8, 0xed, 0x70, 0x68, 0xa2, 0x77, 0x84, 0x49, 0x0e, 0x32, + 0x1c, 0xa0, 0xfe, 0x26, 0xc7, 0x84, 0x94, 0x9f, 0x98, 0x03, 0x4d, 0x93, 0xff, 0x81, 0xa6, 0x9d, + 0xa1, 0x45, 0xa9, 0xff, 0x52, 0x8b, 0xd4, 0x5d, 0x58, 0xac, 0xdb, 0xaf, 0xac, 0x63, 0x5b, 0x37, + 0xa2, 0x3b, 0xe2, 0x05, 0x3e, 0xa1, 0xd4, 0xaf, 0x53, 0xb0, 0x94, 0xf0, 0x5d, 0x80, 0x76, 0x47, + 0xae, 0x02, 0xef, 0xf5, 0x3d, 0x94, 0xb4, 0x0d, 0x1a, 0x90, 0xa1, 0x2a, 0x63, 0x5b, 0x62, 0x63, + 0x9d, 0x25, 0x0c, 0x5b, 0x0c, 0xcc, 0xa9, 0xb8, 0x21, 0x16, 0x2d, 0x7a, 0x06, 0x05, 0x21, 0x12, + 0x34, 0x21, 0x71, 0x48, 0xfd, 0x3f, 0x39, 0x3c, 0x0a, 0xab, 0x13, 0xaf, 0xed, 0x9a, 0x8e, 0x6f, + 0xbb, 0xb5, 0xc5, 0x30, 0x50, 0xe2, 0xc6, 0x18, 0xf8, 0x03, 0x9d, 0x26, 0xf5, 0x0f, 0x19, 0x8a, + 0x07, 0x0e, 0xad, 0xab, 0xd8, 0x60, 0x17, 0xf9, 0x32, 0x7d, 0x32, 0x26, 0x24, 0xd5, 0x24, 0xeb, + 0xb8, 0xb7, 0xca, 0x53, 0x57, 0xb7, 0xbc, 0x0e, 0x71, 0x67, 0x68, 0x89, 0x0a, 0x19, 0x97, 0xe8, + 0x9e, 0x6d, 0x09, 0x29, 0x61, 0x18, 0x3e, 0x82, 0x45, 0xab, 0x7e, 0x02, 0x0b, 0xa3, 0x4c, 0x54, + 0x27, 0x86, 0xf7, 0x95, 0x48, 0x27, 0x00, 0x32, 0x0f, 0xb6, 0x1a, 0x8f, 0x77, 0xea, 0xa5, 0x94, + 0xfa, 0x8b, 0x0c, 0x79, 0x5a, 0x81, 0xed, 0xc3, 0xbe, 0x75, 0x84, 0xf6, 0xd8, 0x36, 0x32, 0x88, + 0x3b, 0x73, 0xe2, 0x29, 0x94, 0x18, 0x98, 0x78, 0x76, 0xdf, 0x6d, 0x53, 0x55, 0x31, 0x88, 0xcb, + 0xe3, 0xe1, 0xc6, 0x9a, 0x84, 0x45, 0x0f, 0x69, 0xfc, 0xda, 0x29, 0x14, 0x60, 0xe3, 0x1c, 0x74, + 0xec, 0x91, 0x97, 0x94, 0x5a, 0x6a, 0x12, 0x66, 0x6d, 0x2d, 0x0b, 0xe9, 0x36, 0x7d, 0xa5, 0xbe, + 0x95, 0xe1, 0x4a, 0x62, 0x08, 0x17, 0x9a, 0x33, 0x15, 0x32, 0x8c, 0x9e, 0xcf, 0x59, 0x9a, 0xa7, + 0xc3, 0x47, 0xb0, 0x68, 0xd1, 0x06, 0xe4, 0xda, 0x87, 0xa4, 0x7d, 0xe4, 0xf5, 0x7b, 0x62, 0x12, + 0x98, 0x4e, 0x47, 0x63, 0x78, 0xd0, 0x43, 0x1f, 0x03, 0x30, 0x9b, 0x96, 0x67, 0xbe, 0x21, 0x4c, + 0xd3, 0xd3, 0xe2, 0x9f, 0x82, 0xc1, 0x28, 0xce, 0xb3, 0xfe, 0x13, 0xf3, 0x0d, 0x51, 0x7f, 0x94, + 0x61, 0x39, 0xa9, 0x0c, 0x17, 0xca, 0x68, 0x9d, 0x46, 0x4b, 0xbd, 0x99, 0x86, 0xc8, 0x49, 0x44, + 0xcb, 0xc7, 0x70, 0x96, 0xf5, 0x1a, 0x06, 0xba, 0x21, 0xe6, 0x88, 0xa6, 0x54, 0x1c, 0x56, 0x5e, + 0xd4, 0xfd, 0xee, 0xaf, 0xef, 0x56, 0xe5, 0xb7, 0xef, 0x56, 0xe5, 0xdf, 0xdf, 0xad, 0xca, 0x2f, + 0x6e, 0x75, 0x4d, 0xff, 0xb0, 0xff, 0xb2, 0xd2, 0xb6, 0x7b, 0x55, 0x16, 0x49, 0x95, 0x45, 0x52, + 0xf5, 0x8c, 0xa3, 0xea, 0xc9, 0x66, 0x95, 0xfd, 0xc3, 0x73, 0x9f, 0xfd, 0xbe, 0xcc, 0xb0, 0xe6, + 0xce, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc1, 0x1f, 0x57, 0x17, 0x9b, 0x12, 0x00, 0x00, } func (m *Command) Marshal() (dAtA []byte, err error) { @@ -1884,6 +1892,13 @@ func (m *NginxConfigStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.NginxId) > 0 { + i -= len(m.NginxId) + copy(dAtA[i:], m.NginxId) + i = encodeVarintCommand(dAtA, i, uint64(len(m.NginxId))) + i-- + dAtA[i] = 0x22 + } if len(m.Message) > 0 { i -= len(m.Message) copy(dAtA[i:], m.Message) @@ -2653,6 +2668,10 @@ func (m *NginxConfigStatus) Size() (n int) { if l > 0 { n += 1 + l + sovCommand(uint64(l)) } + l = len(m.NginxId) + if l > 0 { + n += 1 + l + sovCommand(uint64(l)) + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -4007,6 +4026,38 @@ func (m *NginxConfigStatus) Unmarshal(dAtA []byte) error { } m.Message = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NginxId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommand + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommand + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommand + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NginxId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipCommand(dAtA[iNdEx:]) diff --git a/vendor/github.com/nginx/agent/sdk/v2/proto/command.proto b/vendor/github.com/nginx/agent/sdk/v2/proto/command.proto index 4ae215aa5..feb738c3c 100644 --- a/vendor/github.com/nginx/agent/sdk/v2/proto/command.proto +++ b/vendor/github.com/nginx/agent/sdk/v2/proto/command.proto @@ -103,6 +103,7 @@ message NginxConfigStatus { string correlation_id = 1 [(gogoproto.jsontag) = "correlation_id" ]; Status status = 2 [(gogoproto.jsontag) = "status" ]; string message = 3 [(gogoproto.jsontag) = "message" ]; + string nginx_id = 4 [(gogoproto.jsontag) = "nginx_id" ]; enum Status { PENDING = 0; diff --git a/vendor/github.com/nginx/agent/sdk/v2/proto/events/event.pb.go b/vendor/github.com/nginx/agent/sdk/v2/proto/events/event.pb.go index 0d8ac2fec..903408281 100644 --- a/vendor/github.com/nginx/agent/sdk/v2/proto/events/event.pb.go +++ b/vendor/github.com/nginx/agent/sdk/v2/proto/events/event.pb.go @@ -123,6 +123,7 @@ func (m *Metadata) GetCategory() string { type Event struct { Metadata *Metadata `protobuf:"bytes,1,opt,name=Metadata,proto3" json:"metadata"` // Types that are valid to be assigned to Data: + // // *Event_ActivityEvent // *Event_SecurityViolationEvent Data isEvent_Data `protobuf_oneof:"data"` From a48cc0531bc84734af25c7457363463dbe8c7a93 Mon Sep 17 00:00:00 2001 From: dhurley Date: Fri, 9 Dec 2022 15:17:51 +0000 Subject: [PATCH 8/8] Clean up --- src/plugins/agent_api.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/agent_api.go b/src/plugins/agent_api.go index fe6346543..6a871c37c 100644 --- a/src/plugins/agent_api.go +++ b/src/plugins/agent_api.go @@ -136,7 +136,6 @@ func (a *AgentAPI) Process(message *core.Message) { case core.NginxConfigValidationPending, core.NginxConfigApplyFailed, core.NginxConfigApplySucceeded: switch response := message.Data().(type) { case *proto.AgentActivityStatus: - log.Error(response) nginxConfigStatus := response.GetNginxConfigStatus() a.nginxHandler.configResponseStatuses[nginxConfigStatus.GetNginxId()] = nginxConfigStatus default: