Skip to content

Add ContentUpdateRequest action to MPI - #1977

Open
shaun-nx wants to merge 7 commits into
mainfrom
feat/content-update-request
Open

shaun-nx wants to merge 7 commits into
mainfrom
feat/content-update-request

Conversation

@shaun-nx

@shaun-nx shaun-nx commented Oct 22, 2026 •

Copy link
Copy Markdown

Proposed changes

This PR is one part of issue nginx/nginx-gateway-fabric#5795 to enable NGINX Gateway Fabric to update TLS Certificates without requiring NGINX to reload.

Please see PR nginx/nginx-gateway-fabric#6163 to see how this change integrates.

This change adds a new CONTENT_UPDATE_REQUEST action to the Management Plane Interface. This enables the management plane to push file content updates to the data plane without requesting NGINX config validation or a reload cycle.

Issue nginx/nginx-gateway-fabric#5795

Checklist

Before creating a PR, run through this checklist and mark each as complete.

  • I have read the CONTRIBUTING document
  • I have run make install-tools and have attached any dependency changes to this pull request
  • If applicable, I have added tests that prove my fix is effective or that my feature works
  • If applicable, I have checked that any relevant tests pass after adding my changes
  • If applicable, I have updated any relevant documentation (README.md)
  • If applicable, I have tested my cross-platform changes on Ubuntu 22, Redhat 8, SUSE 15 and FreeBSD 13

@shaun-nx
shaun-nx requested a review from a team as a code owner October 22, 2026 16:43
@github-actions github-actions Bot added chore Pull requests for routine tasks documentation Improvements or additions to documentation enhancement New feature or request labels Oct 22, 2026
@shaun-nx shaun-nx changed the title Feat/content update request Add ContentUpdateRequest action to MPI Oct 22, 2026
@codecov

codecov Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 20.41885% with 152 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.00%. Comparing base (633c0c6) to head (d3604e8).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
internal/nginx/nginx_plugin.go 1.72% 114 Missing ⚠️
internal/command/command_plugin.go 23.07% 30 Missing ⚠️
internal/file/file_manager_service.go 76.47% 8 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1977      +/-   ##
==========================================
- Coverage   88.97%   88.00%   -0.97%     
==========================================
  Files         111      111              
  Lines       12457    12602     +145     
==========================================
+ Hits        11084    11091       +7     
- Misses       1371     1509     +138     
  Partials        2        2              
Files with missing lines Coverage Δ
internal/command/command_service.go 87.46% <100.00%> (+0.07%) ⬆️
internal/file/file_manager_service.go 82.04% <76.47%> (-0.21%) ⬇️
internal/command/command_plugin.go 67.50% <23.07%> (-6.29%) ⬇️
internal/nginx/nginx_plugin.go 62.69% <1.72%> (-18.28%) ⬇️

... and 1 file with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 633c0c6...d3604e8. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Content updates bypass existing request ordering and target-instance validation, allowing stale certificate writes and file mutations for nonexistent targets.

2 open issues
3 files not reviewed
  • api/grpc/mpi/v1/command.pb.go: Generated file
  • api/grpc/mpi/v1/command.pb.validate.go: Generated file
  • internal/file/filefakes/fake_file_manager_service_interface.go: Generated file
What changed in this PR

Adds a file-only update operation to NGINX Agent’s Management Plane Interface, supporting Gateway Fabric’s TLS certificate rotation without NGINX validation or reload.

Changes:

  • Defines ContentUpdateRequest and regenerates protocol bindings, validation, and documentation.
  • Routes content updates through command and NGINX plugins, reusing file processing and rollback logic.
  • Extends test helpers, service fakes, and subscription assertions.
File Description
test/​protos/​management_plane_request.go Adds a content-update request helper.
internal/​nginx/​nginx_plugin.go Handles content updates and rollback without reloading.
internal/​nginx/​nginx_plugin_test.go Checks the new topic subscription.
internal/​file/​filefakes/​fake_file_manager_service_interface.go Adds content-update support to the service fake.
internal/​file/​file_manager_service.go Shares file processing between apply and content updates.
internal/​command/​command_plugin.go Dispatches content updates with feature and server checks.
internal/​bus/​topics.go Defines the content-update topic.
docs/​proto/​protos.md Documents the new protocol operation.
api/​grpc/​mpi/​v1/​command.proto Defines the request and response enum value.
api/​grpc/​mpi/​v1/​command.pb.validate.go Adds generated request validation.
api/​grpc/​mpi/​v1/​command.pb.go Adds generated protocol bindings.

Review effort: Balanced

Comment thread internal/command/command_plugin.go Resolved
func (cp *CommandPlugin) handleContentUpdateRequest(newCtx context.Context, message *mpi.ManagementPlaneRequest) {
cfg := cp.config()
if cfg.IsFeatureEnabled(pkgConfig.FeatureConfiguration) {
cp.messagePipe.Process(newCtx, &bus.Message{Topic: bus.ContentUpdateRequestTopic, Data: message})

@shaun-nx shaun-nx Oct 23, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI generated response by Claude

The queue exists to serialize config applies per instance (which involve validation + reload). Content updates are designed to be a lighter-weight operation (no reload). Whether they truly need to be serialized with config applies depends on the use case. The Copilot scenario (apply A queued, content update C runs before apply B, then B overwrites C's files) is theoretically possible but only if both operations target the same files — which seems unlikely given that content updates are intended for TLS certs while config applies are for nginx config.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open to opinions on this one. I do address with Claude's observation. Files affected by ContentUpdateRequest are logically separated on NGF's side, so they shouldn't go down the same code path.

@salonichf5 salonichf5 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great work with this just had a question

Comment on lines +468 to +493
func (cp *CommandPlugin) handleContentUpdateRequest(newCtx context.Context, message *mpi.ManagementPlaneRequest) {
cfg := cp.config()
if cfg.IsFeatureEnabled(pkgConfig.FeatureConfiguration) {
cp.messagePipe.Process(newCtx, &bus.Message{Topic: bus.ContentUpdateRequestTopic, Data: message})
} else {
slog.WarnContext(
newCtx,
"Configuration feature disabled. Unable to process content update request",
"request", message, "enabled_features", cfg.Features,
)

err := cp.commandService.SendDataPlaneResponse(newCtx, &mpi.DataPlaneResponse{
MessageMeta: message.GetMessageMeta(),
CommandResponse: &mpi.CommandResponse{
Status: mpi.CommandResponse_COMMAND_STATUS_FAILURE,
Message: "Content update failed",
Error: "Configuration feature is disabled",
},
InstanceId: message.GetContentUpdateRequest().GetOverview().GetConfigVersion().GetInstanceId(),
})
if err != nil {
slog.ErrorContext(newCtx, "Unable to send data plane response", "error", err)
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: so only check we do is check if that feature is allowed? Like is it a plus change or not?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is just checking that the configuration feature is enabled. It doesn't check if we're using Plus or OSS though.

Comment thread internal/command/command_plugin.go Resolved
Comment thread internal/command/command_plugin.go Resolved
Comment thread internal/nginx/nginx_plugin.go Resolved
API_ACTION_REQUEST = 5;
COMMAND_STATUS_REQUEST = 6;
UPDATE_AGENT_CONFIG_REQUEST = 7;
CONTENT_UPDATE_REQUEST = 8;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming this is additive, but I want to make sure this API change is a compatible change. I'm not too familiar with protobuf APIs and what is considered additive vs breaking (this feels like additive).

@dhurley

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be additive. The oneof in the ManagementPlaneRequest message adds content_update_request = 10 which wasn't used by any of the other messages (9 was the number before it). This also keeps it backwards compatible since receivers running on older protobufs will just ignore the field, and older senders will never send it too (so no crashes, unhandled messages)

@Akshay2191 Akshay2191 added the v3.x Issues and Pull Requests related to the major version v3 label Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Pull requests for routine tasks documentation Improvements or additions to documentation enhancement New feature or request v3.x Issues and Pull Requests related to the major version v3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants