airbyte-internal-ops 0.9.1__py3-none-any.whl → 0.10.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,7 @@ from airbyte_ops_mcp.prod_db_access.queries import (
23
23
  query_connections_by_connector,
24
24
  query_connections_by_destination_connector,
25
25
  query_connections_by_stream,
26
+ query_connector_rollouts,
26
27
  query_connector_versions,
27
28
  query_dataplanes_list,
28
29
  query_destination_connection_stats,
@@ -1272,6 +1273,145 @@ def query_prod_connector_connection_stats(
1272
1273
  )
1273
1274
 
1274
1275
 
1276
+ # =============================================================================
1277
+ # Connector Rollout Models and Tools
1278
+ # =============================================================================
1279
+
1280
+
1281
+ class ConnectorRolloutInfo(BaseModel):
1282
+ """Information about a connector rollout."""
1283
+
1284
+ rollout_id: str = Field(description="The rollout UUID")
1285
+ actor_definition_id: str = Field(description="The connector definition UUID")
1286
+ state: str = Field(
1287
+ description="Rollout state: initialized, workflow_started, in_progress, "
1288
+ "paused, finalizing, succeeded, errored, failed_rolled_back, canceled"
1289
+ )
1290
+ initial_rollout_pct: int | None = Field(
1291
+ default=None, description="Initial rollout percentage"
1292
+ )
1293
+ current_target_rollout_pct: int | None = Field(
1294
+ default=None, description="Current target rollout percentage"
1295
+ )
1296
+ final_target_rollout_pct: int | None = Field(
1297
+ default=None, description="Final target rollout percentage"
1298
+ )
1299
+ has_breaking_changes: bool = Field(
1300
+ description="Whether the RC has breaking changes"
1301
+ )
1302
+ max_step_wait_time_mins: int | None = Field(
1303
+ default=None, description="Maximum wait time between rollout steps in minutes"
1304
+ )
1305
+ rollout_strategy: str | None = Field(
1306
+ default=None, description="Rollout strategy: manual, automated, overridden"
1307
+ )
1308
+ workflow_run_id: str | None = Field(
1309
+ default=None, description="Temporal workflow run ID"
1310
+ )
1311
+ error_msg: str | None = Field(default=None, description="Error message if errored")
1312
+ failed_reason: str | None = Field(
1313
+ default=None, description="Reason for failure if failed"
1314
+ )
1315
+ paused_reason: str | None = Field(
1316
+ default=None, description="Reason for pause if paused"
1317
+ )
1318
+ tag: str | None = Field(default=None, description="Optional tag for the rollout")
1319
+ created_at: datetime | None = Field(
1320
+ default=None, description="When the rollout was created"
1321
+ )
1322
+ updated_at: datetime | None = Field(
1323
+ default=None, description="When the rollout was last updated"
1324
+ )
1325
+ completed_at: datetime | None = Field(
1326
+ default=None, description="When the rollout completed (if terminal)"
1327
+ )
1328
+ expires_at: datetime | None = Field(
1329
+ default=None, description="When the rollout expires"
1330
+ )
1331
+ rc_docker_image_tag: str | None = Field(
1332
+ default=None, description="Docker image tag of the release candidate"
1333
+ )
1334
+ rc_docker_repository: str | None = Field(
1335
+ default=None, description="Docker repository of the release candidate"
1336
+ )
1337
+ initial_docker_image_tag: str | None = Field(
1338
+ default=None, description="Docker image tag of the initial version"
1339
+ )
1340
+ initial_docker_repository: str | None = Field(
1341
+ default=None, description="Docker repository of the initial version"
1342
+ )
1343
+
1344
+
1345
+ def _row_to_connector_rollout_info(row: dict[str, Any]) -> ConnectorRolloutInfo:
1346
+ """Convert a database row to a ConnectorRolloutInfo model."""
1347
+ return ConnectorRolloutInfo(
1348
+ rollout_id=str(row["rollout_id"]),
1349
+ actor_definition_id=str(row["actor_definition_id"]),
1350
+ state=row["state"],
1351
+ initial_rollout_pct=row.get("initial_rollout_pct"),
1352
+ current_target_rollout_pct=row.get("current_target_rollout_pct"),
1353
+ final_target_rollout_pct=row.get("final_target_rollout_pct"),
1354
+ has_breaking_changes=row["has_breaking_changes"],
1355
+ max_step_wait_time_mins=row.get("max_step_wait_time_mins"),
1356
+ rollout_strategy=row.get("rollout_strategy"),
1357
+ workflow_run_id=row.get("workflow_run_id"),
1358
+ error_msg=row.get("error_msg"),
1359
+ failed_reason=row.get("failed_reason"),
1360
+ paused_reason=row.get("paused_reason"),
1361
+ tag=row.get("tag"),
1362
+ created_at=row.get("created_at"),
1363
+ updated_at=row.get("updated_at"),
1364
+ completed_at=row.get("completed_at"),
1365
+ expires_at=row.get("expires_at"),
1366
+ rc_docker_image_tag=row.get("rc_docker_image_tag"),
1367
+ rc_docker_repository=row.get("rc_docker_repository"),
1368
+ initial_docker_image_tag=row.get("initial_docker_image_tag"),
1369
+ initial_docker_repository=row.get("initial_docker_repository"),
1370
+ )
1371
+
1372
+
1373
+ @mcp_tool(
1374
+ read_only=True,
1375
+ idempotent=True,
1376
+ )
1377
+ def query_prod_connector_rollouts(
1378
+ actor_definition_id: Annotated[
1379
+ str | None,
1380
+ Field(description="Connector definition UUID to filter by (optional)"),
1381
+ ] = None,
1382
+ rollout_id: Annotated[
1383
+ str | None,
1384
+ Field(description="Specific rollout UUID to look up (optional)"),
1385
+ ] = None,
1386
+ active_only: Annotated[
1387
+ bool,
1388
+ Field(description="If true, only return active (non-terminal) rollouts"),
1389
+ ] = False,
1390
+ limit: Annotated[
1391
+ int,
1392
+ Field(description="Maximum number of results (default: 100)"),
1393
+ ] = 100,
1394
+ ) -> list[ConnectorRolloutInfo]:
1395
+ """Query connector rollouts with flexible filtering.
1396
+
1397
+ Returns rollouts based on the provided filters. If no filters are specified,
1398
+ returns all active rollouts. Useful for monitoring rollout status and history.
1399
+
1400
+ Filter behavior:
1401
+ - rollout_id: Returns that specific rollout (ignores other filters)
1402
+ - active_only: Returns only active (non-terminal) rollouts
1403
+ - actor_definition_id: Returns rollouts for that specific connector
1404
+ - No filters: Returns all active rollouts (same as active_only=True)
1405
+ """
1406
+ rows = query_connector_rollouts(
1407
+ actor_definition_id=actor_definition_id,
1408
+ rollout_id=rollout_id,
1409
+ active_only=active_only,
1410
+ limit=limit,
1411
+ )
1412
+ return [_row_to_connector_rollout_info(row) for row in rows]
1413
+
1414
+
1275
1415
  def register_prod_db_query_tools(app: FastMCP) -> None:
1276
1416
  """Register prod DB query tools with the FastMCP app."""
1277
1417
  register_mcp_tools(app, mcp_module=__name__)
@@ -33,6 +33,7 @@ from airbyte_ops_mcp.mcp._guidance import MCP_SERVER_INSTRUCTIONS
33
33
  from airbyte_ops_mcp.mcp.cloud_connector_versions import (
34
34
  register_cloud_connector_version_tools,
35
35
  )
36
+ from airbyte_ops_mcp.mcp.connector_rollout import register_connector_rollout_tools
36
37
  from airbyte_ops_mcp.mcp.gcp_logs import register_gcp_logs_tools
37
38
  from airbyte_ops_mcp.mcp.github_actions import register_github_actions_tools
38
39
  from airbyte_ops_mcp.mcp.github_repo_ops import register_github_repo_ops_tools
@@ -117,6 +118,7 @@ def register_server_assets(app: FastMCP) -> None:
117
118
  register_github_actions_tools(app)
118
119
  register_prerelease_tools(app)
119
120
  register_cloud_connector_version_tools(app)
121
+ register_connector_rollout_tools(app)
120
122
  register_prod_db_query_tools(app)
121
123
  register_gcp_logs_tools(app)
122
124
  register_prompts(app)
@@ -19,6 +19,8 @@ from google.cloud import secretmanager
19
19
  from airbyte_ops_mcp.gcp_auth import get_secret_manager_client
20
20
  from airbyte_ops_mcp.prod_db_access.db_engine import get_pool
21
21
  from airbyte_ops_mcp.prod_db_access.sql import (
22
+ SELECT_ACTIVE_CONNECTOR_ROLLOUTS,
23
+ SELECT_ACTIVE_CONNECTOR_ROLLOUTS_BY_DEFINITION,
22
24
  SELECT_ACTORS_PINNED_TO_VERSION,
23
25
  SELECT_CONNECTIONS_BY_CONNECTOR,
24
26
  SELECT_CONNECTIONS_BY_CONNECTOR_AND_ORG,
@@ -26,6 +28,8 @@ from airbyte_ops_mcp.prod_db_access.sql import (
26
28
  SELECT_CONNECTIONS_BY_DESTINATION_CONNECTOR_AND_ORG,
27
29
  SELECT_CONNECTIONS_BY_SOURCE_CONNECTOR_AND_STREAM,
28
30
  SELECT_CONNECTIONS_BY_SOURCE_CONNECTOR_AND_STREAM_AND_ORG,
31
+ SELECT_CONNECTOR_ROLLOUT_BY_ID,
32
+ SELECT_CONNECTOR_ROLLOUTS,
29
33
  SELECT_CONNECTOR_VERSIONS,
30
34
  SELECT_DATAPLANES_LIST,
31
35
  SELECT_DESTINATION_CONNECTION_STATS,
@@ -616,3 +620,82 @@ def query_connections_by_stream(
616
620
  query_name="SELECT_CONNECTIONS_BY_SOURCE_CONNECTOR_AND_STREAM_AND_ORG",
617
621
  gsm_client=gsm_client,
618
622
  )
623
+
624
+
625
+ def query_connector_rollouts(
626
+ actor_definition_id: str | None = None,
627
+ rollout_id: str | None = None,
628
+ active_only: bool = False,
629
+ limit: int = 100,
630
+ *,
631
+ gsm_client: secretmanager.SecretManagerServiceClient | None = None,
632
+ ) -> list[dict[str, Any]]:
633
+ """Query connector rollouts with flexible filtering.
634
+
635
+ This is the unified query function for connector rollouts. Based on the
636
+ arguments provided, it will:
637
+ - If rollout_id is provided: Return that specific rollout (as a single-item list)
638
+ - If active_only is True AND actor_definition_id is provided: Return active rollouts for that connector
639
+ - If active_only is True: Return all active (non-terminal) rollouts
640
+ - If actor_definition_id is provided: Return all rollouts for that connector (including terminal)
641
+ - Otherwise: Return all active rollouts (up to limit)
642
+
643
+ Args:
644
+ actor_definition_id: Optional connector definition UUID to filter by
645
+ rollout_id: Optional specific rollout UUID to look up
646
+ active_only: If True, only return active (non-terminal) rollouts
647
+ limit: Maximum number of results (default: 100)
648
+ gsm_client: GCP Secret Manager client. If None, a new client will be instantiated.
649
+
650
+ Returns:
651
+ List of rollout records with version details
652
+ """
653
+ if rollout_id is not None:
654
+ rows = _run_sql_query(
655
+ SELECT_CONNECTOR_ROLLOUT_BY_ID,
656
+ parameters={"rollout_id": rollout_id},
657
+ query_name="SELECT_CONNECTOR_ROLLOUT_BY_ID",
658
+ gsm_client=gsm_client,
659
+ )
660
+ return rows
661
+
662
+ # Handle active_only with optional actor_definition_id filter
663
+ if active_only:
664
+ if actor_definition_id is not None:
665
+ # Filter by both active states AND actor_definition_id
666
+ return _run_sql_query(
667
+ SELECT_ACTIVE_CONNECTOR_ROLLOUTS_BY_DEFINITION,
668
+ parameters={
669
+ "actor_definition_id": actor_definition_id,
670
+ "limit": limit,
671
+ },
672
+ query_name="SELECT_ACTIVE_CONNECTOR_ROLLOUTS_BY_DEFINITION",
673
+ gsm_client=gsm_client,
674
+ )
675
+ # Only active filter, no actor_definition_id
676
+ return _run_sql_query(
677
+ SELECT_ACTIVE_CONNECTOR_ROLLOUTS,
678
+ parameters={"limit": limit},
679
+ query_name="SELECT_ACTIVE_CONNECTOR_ROLLOUTS",
680
+ gsm_client=gsm_client,
681
+ )
682
+
683
+ # Not active_only, but filter by actor_definition_id (all states)
684
+ if actor_definition_id is not None:
685
+ return _run_sql_query(
686
+ SELECT_CONNECTOR_ROLLOUTS,
687
+ parameters={
688
+ "actor_definition_id": actor_definition_id,
689
+ "limit": limit,
690
+ },
691
+ query_name="SELECT_CONNECTOR_ROLLOUTS",
692
+ gsm_client=gsm_client,
693
+ )
694
+
695
+ # Default: return active rollouts if no filters specified
696
+ return _run_sql_query(
697
+ SELECT_ACTIVE_CONNECTOR_ROLLOUTS,
698
+ parameters={"limit": limit},
699
+ query_name="SELECT_ACTIVE_CONNECTOR_ROLLOUTS",
700
+ gsm_client=gsm_client,
701
+ )
@@ -64,6 +64,19 @@ attempts
64
64
  --------
65
65
  id, job_id, attempt_number, log_path, output, status, created_at, updated_at,
66
66
  ended_at, failure_summary, processing_task_queue, attempt_sync_config
67
+
68
+ connector_rollout
69
+ -----------------
70
+ id, actor_definition_id, release_candidate_version_id, initial_version_id, state,
71
+ initial_rollout_pct, current_target_rollout_pct, final_target_rollout_pct,
72
+ has_breaking_changes, max_step_wait_time_mins, updated_by, created_at, updated_at,
73
+ completed_at, expires_at, error_msg, failed_reason, rollout_strategy, workflow_run_id,
74
+ paused_reason, filters, tag
75
+
76
+ Note: state values: 'initialized', 'workflow_started', 'in_progress', 'paused',
77
+ 'finalizing', 'succeeded', 'errored', 'failed_rolled_back', 'canceled'
78
+ Active states: initialized, workflow_started, in_progress, paused, finalizing, errored
79
+ Terminal states: succeeded, failed_rolled_back, canceled
67
80
  """
68
81
 
69
82
  from __future__ import annotations
@@ -1010,3 +1023,197 @@ SELECT_CONNECTIONS_BY_SOURCE_CONNECTOR_AND_STREAM_AND_ORG = sqlalchemy.text(
1010
1023
  LIMIT :limit
1011
1024
  """
1012
1025
  )
1026
+
1027
+ # =============================================================================
1028
+ # Connector Rollout Queries
1029
+ # =============================================================================
1030
+
1031
+ # List all rollouts for a connector definition, with version details
1032
+ SELECT_CONNECTOR_ROLLOUTS = sqlalchemy.text(
1033
+ """
1034
+ SELECT
1035
+ cr.id AS rollout_id,
1036
+ cr.actor_definition_id,
1037
+ cr.state,
1038
+ cr.initial_rollout_pct,
1039
+ cr.current_target_rollout_pct,
1040
+ cr.final_target_rollout_pct,
1041
+ cr.has_breaking_changes,
1042
+ cr.max_step_wait_time_mins,
1043
+ cr.rollout_strategy,
1044
+ cr.workflow_run_id,
1045
+ cr.error_msg,
1046
+ cr.failed_reason,
1047
+ cr.paused_reason,
1048
+ cr.tag,
1049
+ cr.created_at,
1050
+ cr.updated_at,
1051
+ cr.completed_at,
1052
+ cr.expires_at,
1053
+ rc_version.docker_image_tag AS rc_docker_image_tag,
1054
+ rc_version.docker_repository AS rc_docker_repository,
1055
+ initial_version.docker_image_tag AS initial_docker_image_tag,
1056
+ initial_version.docker_repository AS initial_docker_repository
1057
+ FROM connector_rollout cr
1058
+ JOIN actor_definition_version rc_version
1059
+ ON cr.release_candidate_version_id = rc_version.id
1060
+ LEFT JOIN actor_definition_version initial_version
1061
+ ON cr.initial_version_id = initial_version.id
1062
+ WHERE
1063
+ cr.actor_definition_id = :actor_definition_id
1064
+ ORDER BY
1065
+ cr.created_at DESC
1066
+ LIMIT :limit
1067
+ """
1068
+ )
1069
+
1070
+ # List all active (non-terminal) rollouts across all connectors
1071
+ # Active states: initialized, workflow_started, in_progress, paused, finalizing, errored
1072
+ SELECT_ACTIVE_CONNECTOR_ROLLOUTS = sqlalchemy.text(
1073
+ """
1074
+ SELECT
1075
+ cr.id AS rollout_id,
1076
+ cr.actor_definition_id,
1077
+ cr.state,
1078
+ cr.initial_rollout_pct,
1079
+ cr.current_target_rollout_pct,
1080
+ cr.final_target_rollout_pct,
1081
+ cr.has_breaking_changes,
1082
+ cr.max_step_wait_time_mins,
1083
+ cr.rollout_strategy,
1084
+ cr.workflow_run_id,
1085
+ cr.error_msg,
1086
+ cr.failed_reason,
1087
+ cr.paused_reason,
1088
+ cr.tag,
1089
+ cr.created_at,
1090
+ cr.updated_at,
1091
+ cr.completed_at,
1092
+ cr.expires_at,
1093
+ rc_version.docker_image_tag AS rc_docker_image_tag,
1094
+ rc_version.docker_repository AS rc_docker_repository,
1095
+ initial_version.docker_image_tag AS initial_docker_image_tag,
1096
+ initial_version.docker_repository AS initial_docker_repository
1097
+ FROM connector_rollout cr
1098
+ JOIN actor_definition_version rc_version
1099
+ ON cr.release_candidate_version_id = rc_version.id
1100
+ LEFT JOIN actor_definition_version initial_version
1101
+ ON cr.initial_version_id = initial_version.id
1102
+ WHERE
1103
+ cr.state IN ('initialized', 'workflow_started', 'in_progress', 'paused', 'finalizing', 'errored')
1104
+ ORDER BY
1105
+ cr.created_at DESC
1106
+ LIMIT :limit
1107
+ """
1108
+ )
1109
+
1110
+ # List active (non-terminal) rollouts for a specific connector definition
1111
+ # Active states: initialized, workflow_started, in_progress, paused, finalizing, errored
1112
+ SELECT_ACTIVE_CONNECTOR_ROLLOUTS_BY_DEFINITION = sqlalchemy.text(
1113
+ """
1114
+ SELECT
1115
+ cr.id AS rollout_id,
1116
+ cr.actor_definition_id,
1117
+ cr.state,
1118
+ cr.initial_rollout_pct,
1119
+ cr.current_target_rollout_pct,
1120
+ cr.final_target_rollout_pct,
1121
+ cr.has_breaking_changes,
1122
+ cr.max_step_wait_time_mins,
1123
+ cr.rollout_strategy,
1124
+ cr.workflow_run_id,
1125
+ cr.error_msg,
1126
+ cr.failed_reason,
1127
+ cr.paused_reason,
1128
+ cr.tag,
1129
+ cr.created_at,
1130
+ cr.updated_at,
1131
+ cr.completed_at,
1132
+ cr.expires_at,
1133
+ rc_version.docker_image_tag AS rc_docker_image_tag,
1134
+ rc_version.docker_repository AS rc_docker_repository,
1135
+ initial_version.docker_image_tag AS initial_docker_image_tag,
1136
+ initial_version.docker_repository AS initial_docker_repository
1137
+ FROM connector_rollout cr
1138
+ JOIN actor_definition_version rc_version
1139
+ ON cr.release_candidate_version_id = rc_version.id
1140
+ LEFT JOIN actor_definition_version initial_version
1141
+ ON cr.initial_version_id = initial_version.id
1142
+ WHERE
1143
+ cr.actor_definition_id = :actor_definition_id
1144
+ AND cr.state IN ('initialized', 'workflow_started', 'in_progress', 'paused', 'finalizing', 'errored')
1145
+ ORDER BY
1146
+ cr.created_at DESC
1147
+ LIMIT :limit
1148
+ """
1149
+ )
1150
+
1151
+ # Get a specific rollout by ID
1152
+ SELECT_CONNECTOR_ROLLOUT_BY_ID = sqlalchemy.text(
1153
+ """
1154
+ SELECT
1155
+ cr.id AS rollout_id,
1156
+ cr.actor_definition_id,
1157
+ cr.state,
1158
+ cr.initial_rollout_pct,
1159
+ cr.current_target_rollout_pct,
1160
+ cr.final_target_rollout_pct,
1161
+ cr.has_breaking_changes,
1162
+ cr.max_step_wait_time_mins,
1163
+ cr.rollout_strategy,
1164
+ cr.workflow_run_id,
1165
+ cr.error_msg,
1166
+ cr.failed_reason,
1167
+ cr.paused_reason,
1168
+ cr.filters,
1169
+ cr.tag,
1170
+ cr.created_at,
1171
+ cr.updated_at,
1172
+ cr.completed_at,
1173
+ cr.expires_at,
1174
+ rc_version.docker_image_tag AS rc_docker_image_tag,
1175
+ rc_version.docker_repository AS rc_docker_repository,
1176
+ initial_version.docker_image_tag AS initial_docker_image_tag,
1177
+ initial_version.docker_repository AS initial_docker_repository
1178
+ FROM connector_rollout cr
1179
+ JOIN actor_definition_version rc_version
1180
+ ON cr.release_candidate_version_id = rc_version.id
1181
+ LEFT JOIN actor_definition_version initial_version
1182
+ ON cr.initial_version_id = initial_version.id
1183
+ WHERE
1184
+ cr.id = :rollout_id
1185
+ """
1186
+ )
1187
+
1188
+ # =============================================================================
1189
+ # Connector Rollout Monitoring Queries
1190
+ # =============================================================================
1191
+
1192
+ # Get actors pinned to a specific rollout (via scoped_configuration.origin = rollout_id)
1193
+ # This shows which actors are currently participating in the rollout
1194
+ SELECT_ACTORS_PINNED_TO_ROLLOUT = sqlalchemy.text(
1195
+ """
1196
+ SELECT
1197
+ actor.id AS actor_id,
1198
+ actor.name AS actor_name,
1199
+ actor.actor_definition_id,
1200
+ actor.workspace_id,
1201
+ workspace.name AS workspace_name,
1202
+ workspace.organization_id,
1203
+ scoped_configuration.origin_type AS pin_origin_type,
1204
+ scoped_configuration.origin AS pin_origin,
1205
+ scoped_configuration.created_at AS pin_created_at,
1206
+ scoped_configuration.value AS pinned_version_id
1207
+ FROM scoped_configuration
1208
+ JOIN actor
1209
+ ON scoped_configuration.scope_id = actor.id
1210
+ JOIN workspace
1211
+ ON actor.workspace_id = workspace.id
1212
+ WHERE
1213
+ scoped_configuration.key = 'connector_version'
1214
+ AND scoped_configuration.scope_type = 'actor'
1215
+ AND scoped_configuration.origin = :rollout_id
1216
+ ORDER BY
1217
+ scoped_configuration.created_at DESC
1218
+ """
1219
+ )