@@ -8,9 +8,15 @@ package bus
88import (
99 "context"
1010 "log/slog"
11+ "reflect"
1112 "sync"
1213
14+ mpi "github.com/nginx/agent/v3/api/grpc/mpi/v1"
15+ "github.com/nginx/agent/v3/internal/config"
16+ "github.com/nginx/agent/v3/internal/logger"
17+ "github.com/nginx/agent/v3/pkg/id"
1318 messagebus "github.com/vardius/message-bus"
19+ "google.golang.org/protobuf/types/known/timestamppb"
1420)
1521
1622type (
@@ -45,20 +51,24 @@ type (
4551 Info () * Info
4652 Process (ctx context.Context , msg * Message )
4753 Subscriptions () []string
54+ Reconfigure (ctx context.Context , agentConfig * config.Config ) error
4855 }
4956
5057 MessagePipe struct {
58+ agentConfig * config.Config
5159 bus messagebus.MessageBus
5260 messageChannel chan * MessageWithContext
5361 plugins []Plugin
5462 pluginsMutex sync.Mutex
63+ configMutex sync.Mutex
5564 }
5665)
5766
58- func NewMessagePipe (size int ) * MessagePipe {
67+ func NewMessagePipe (size int , agentConfig * config. Config ) * MessagePipe {
5968 return & MessagePipe {
6069 messageChannel : make (chan * MessageWithContext , size ),
6170 pluginsMutex : sync.Mutex {},
71+ agentConfig : agentConfig ,
6272 }
6373}
6474
@@ -110,6 +120,7 @@ func (p *MessagePipe) Process(ctx context.Context, messages ...*Message) {
110120 }
111121}
112122
123+ //nolint:contextcheck,revive // need to use context from the message for the correlationID not use the parent context
113124func (p * MessagePipe ) Run (ctx context.Context ) {
114125 p .pluginsMutex .Lock ()
115126 p .initPlugins (ctx )
@@ -126,7 +137,17 @@ func (p *MessagePipe) Run(ctx context.Context) {
126137
127138 return
128139 case m := <- p .messageChannel :
129- p .bus .Publish (m .message .Topic , m .ctx , m .message )
140+ if m .message != nil {
141+ switch m .message .Topic {
142+ case AgentConfigUpdateTopic :
143+ p .handleAgentConfigUpdateTopic (m .ctx , m .message )
144+ case ConnectionAgentConfigUpdateTopic :
145+ p .handleConnectionAgentConfigUpdateTopic (m .ctx , m .message )
146+ default :
147+ slog .InfoContext (ctx , "Publishing message" , "topic" , m .message .Topic , "message----" , m .message )
148+ p .bus .Publish (m .message .Topic , m .ctx , m .message )
149+ }
150+ }
130151 }
131152 }
132153}
@@ -157,6 +178,114 @@ func (p *MessagePipe) Index(pluginName string, plugins []Plugin) int {
157178 return - 1
158179}
159180
181+ func (p * MessagePipe ) Reconfigure (ctx context.Context , agentConfig * mpi.AgentConfig , topic , correlationID string ) {
182+ var reconfigureError error
183+ p .configMutex .Lock ()
184+ defer p .configMutex .Unlock ()
185+ currentConfig := p .agentConfig
186+
187+ // convert agent config from *mpi.AgentConfig to *config.Config
188+ updateAgentConfig := config .FromAgentRemoteConfigProto (agentConfig )
189+
190+ // The check for updates to the config needs to be done here as the command plugin needs the latest agent config
191+ // to be sent in response to create connection requests.
192+ p .updateConfig (ctx , updateAgentConfig )
193+
194+ // Reconfigure each plugin with the new agent config
195+ for _ , plugin := range p .plugins {
196+ slog .InfoContext (ctx , "Reconfigure plugin" , "plugin" , plugin .Info ().Name )
197+ reconfigureError = plugin .Reconfigure (ctx , p .agentConfig )
198+ if reconfigureError != nil {
199+ slog .ErrorContext (ctx , "Reconfigure plugin failed" , "plugin" , plugin .Info ().Name )
200+ break
201+ }
202+ }
203+
204+ if reconfigureError != nil {
205+ slog .ErrorContext (ctx , "Error updating plugin with updated agent config, reverting" ,
206+ "error" , reconfigureError .Error ())
207+
208+ // If the agent update was received from a create connection request no data plane response needs to be sent
209+ if topic == AgentConfigUpdateTopic {
210+ response := p .createDataPlaneResponse (correlationID , mpi .CommandResponse_COMMAND_STATUS_FAILURE ,
211+ "Failed to update agent config" , reconfigureError .Error ())
212+ p .bus .Publish (DataPlaneResponseTopic , ctx , & Message {Topic : DataPlaneResponseTopic , Data : response })
213+ }
214+
215+ p .agentConfig = currentConfig
216+ for _ , plugin := range p .plugins {
217+ err := plugin .Reconfigure (ctx , currentConfig )
218+ if err != nil {
219+ slog .ErrorContext (ctx , "Error reverting agent config" , "error" , err .Error ())
220+ }
221+ }
222+ }
223+
224+ slog .InfoContext (ctx , "Finished reconfigure plugin" , "plugins" , p .plugins )
225+ if topic == AgentConfigUpdateTopic {
226+ response := p .createDataPlaneResponse (correlationID , mpi .CommandResponse_COMMAND_STATUS_OK ,
227+ "Successfully updated agent config" , "" )
228+ p .bus .Publish (DataPlaneResponseTopic , ctx , & Message {Topic : DataPlaneResponseTopic , Data : response })
229+ }
230+ }
231+
232+ func (p * MessagePipe ) handleConnectionAgentConfigUpdateTopic (ctx context.Context , msg * Message ) {
233+ slog .DebugContext (ctx , "Handling connection agent config update topic" , "topic" , msg .Topic )
234+ agentConfig , ok := msg .Data .(* mpi.AgentConfig )
235+ if ! ok {
236+ slog .ErrorContext (ctx , "Failed to parse agent config update message" )
237+ return
238+ }
239+
240+ p .Reconfigure (ctx , agentConfig , msg .Topic , "" )
241+ }
242+
243+ func (p * MessagePipe ) handleAgentConfigUpdateTopic (ctx context.Context , msg * Message ) {
244+ slog .DebugContext (ctx , "Received agent config update topic" , "topic" , msg .Topic )
245+ mpRequest , ok := msg .Data .(* mpi.ManagementPlaneRequest )
246+ if ! ok {
247+ slog .ErrorContext (ctx , "Failed to parse agent config update message" )
248+ return
249+ }
250+
251+ reconfigureRequest , ok := mpRequest .GetRequest ().(* mpi.ManagementPlaneRequest_UpdateAgentConfigRequest )
252+ if ! ok {
253+ slog .ErrorContext (ctx , "Failed to parse agent config update message" )
254+ return
255+ }
256+
257+ correlationID := reconfigureRequest .UpdateAgentConfigRequest .GetMessageMeta ().GetCorrelationId ()
258+ p .Reconfigure (ctx , reconfigureRequest .UpdateAgentConfigRequest .GetAgentConfig (), msg .Topic , correlationID )
259+ }
260+
261+ func (p * MessagePipe ) updateConfig (ctx context.Context , updateAgentConfig * config.Config ) {
262+ slog .InfoContext (ctx , "Updating agent config" )
263+ if updateAgentConfig .Log != nil && ! reflect .DeepEqual (p .agentConfig .Log , updateAgentConfig .Log ) {
264+ slog .DebugContext (ctx , "Agent log level has been updated" , "previous" , p .agentConfig .Log ,
265+ "update" , updateAgentConfig .Log )
266+ p .agentConfig .Log = updateAgentConfig .Log
267+
268+ slogger := logger .New (
269+ p .agentConfig .Log .Path ,
270+ p .agentConfig .Log .Level ,
271+ )
272+ slog .SetDefault (slogger )
273+ }
274+
275+ if updateAgentConfig .Labels != nil && ! reflect .DeepEqual (p .agentConfig .Labels , updateAgentConfig .Labels ) {
276+ slog .DebugContext (ctx , "Agent labels have been updated" , "previous" , p .agentConfig .Labels ,
277+ "update" , updateAgentConfig .Labels )
278+ p .agentConfig .Labels = updateAgentConfig .Labels
279+
280+ // OTel Headers also need to be updated when labels have been updated
281+ if p .agentConfig .Collector != nil {
282+ slog .DebugContext (ctx , "Agent OTel headers have been updated" )
283+ config .AddLabelsAsOTelHeaders (p .agentConfig .Collector , updateAgentConfig .Labels )
284+ }
285+ }
286+ slog .DebugContext (ctx , "Updated agent config" )
287+ }
288+
160289func (p * MessagePipe ) unsubscribePlugin (ctx context.Context , index int , plugin Plugin ) error {
161290 if index != - 1 {
162291 p .plugins = append (p .plugins [:index ], p .plugins [index + 1 :]... )
@@ -209,3 +338,20 @@ func (p *MessagePipe) initPlugins(ctx context.Context) {
209338 }
210339 }
211340}
341+
342+ func (p * MessagePipe ) createDataPlaneResponse (correlationID string , status mpi.CommandResponse_CommandStatus ,
343+ message , err string ,
344+ ) * mpi.DataPlaneResponse {
345+ return & mpi.DataPlaneResponse {
346+ MessageMeta : & mpi.MessageMeta {
347+ MessageId : id .GenerateMessageID (),
348+ CorrelationId : correlationID ,
349+ Timestamp : timestamppb .Now (),
350+ },
351+ CommandResponse : & mpi.CommandResponse {
352+ Status : status ,
353+ Message : message ,
354+ Error : err ,
355+ },
356+ }
357+ }
0 commit comments