feat(pageserver): add force patch index_part API (#11119)

## Problem

As part of the disaster recovery tool. Partly for
https://github.com/neondatabase/neon/issues/9114.

## Summary of changes

* Add a new pageserver API to force patch the fields in index_part and
modify the timeline internal structures.

---------

Signed-off-by: Alex Chi Z <chi@neon.tech>
This commit is contained in:
Alex Chi Z.
2025-03-07 12:42:52 -05:00
committed by GitHub
parent e876794ce5
commit cd438406fb
5 changed files with 129 additions and 2 deletions

View File

@@ -375,6 +375,19 @@ class PageserverHttpClient(requests.Session, MetricsGetter):
res = self.post(f"http://localhost:{self.port}/v1/tenant/{tenant_id}/reset", params=params)
self.verbose_error(res)
def timeline_patch_index_part(
self,
tenant_id: TenantId | TenantShardId,
timeline_id: TimelineId,
data: dict[str, Any],
):
res = self.post(
f"http://localhost:{self.port}/v1/tenant/{tenant_id}/timeline/{timeline_id}/patch_index_part",
json=data,
)
self.verbose_error(res)
return res.json()
def tenant_location_conf(
self,
tenant_id: TenantId | TenantShardId,

View File

@@ -7,7 +7,7 @@ from fixtures.neon_fixtures import (
NeonEnvBuilder,
)
from fixtures.pageserver.http import PageserverHttpClient
from fixtures.utils import wait_until
from fixtures.utils import run_only_on_default_postgres, wait_until
def check_client(env: NeonEnv, client: PageserverHttpClient):
@@ -138,3 +138,25 @@ def test_pageserver_http_api_client_auth_enabled(neon_env_builder: NeonEnvBuilde
with env.pageserver.http_client(auth_token=pageserver_token) as client:
check_client(env, client)
@run_only_on_default_postgres("it does not use any postgres functionality")
def test_pageserver_http_index_part_force_patch(neon_env_builder: NeonEnvBuilder):
env = neon_env_builder.init_start()
tenant_id = env.initial_tenant
timeline_id = env.initial_timeline
with env.pageserver.http_client() as client:
client.timeline_patch_index_part(
tenant_id,
timeline_id,
{"rel_size_migration": "migrating"},
)
assert client.timeline_detail(tenant_id, timeline_id)["rel_size_migration"] == "migrating"
# This is invalid in practice: we should never rollback the migrating state to legacy.
# But we do it here to test the API.
client.timeline_patch_index_part(
tenant_id,
timeline_id,
{"rel_size_migration": "legacy"},
)
assert client.timeline_detail(tenant_id, timeline_id)["rel_size_migration"] == "legacy"