{
  "repo": "tidbcloud/aws-shared-provider",
  "binary": "ops-service",
  "binary_path": "cmd/ops-service/main.go",
  "dependencies": {
    "OpsServiceLifecycle.LoadFlags": {
      "infrastructure": {},
      "services": []
    },
    "OpsServiceLifecycle.BuildKubeConfig": {
      "infrastructure": {
        "filesystem": {
          "conditions": [
            "--kubeconfig is not empty"
          ],
          "operations": [
            {
              "operation": "READ",
              "trigger": "Load kubeconfig for the Kubernetes clients used by ops-service",
              "conditions": [
                "Only when the kubeconfig flag points to a file"
              ],
              "implementation": "clientcmd.BuildConfigFromFlags(\"\", kubeConfigPath)"
            }
          ]
        }
      },
      "services": []
    },
    "OpsServiceLifecycle.InitKubernetesClients": {
      "infrastructure": {},
      "services": []
    },
    "OpsServiceLifecycle.InitTLSCertificate": {
      "infrastructure": {
        "filesystem": {
          "conditions": [
            "Always before the HTTPS server starts"
          ],
          "operations": [
            {
              "operation": "READ",
              "trigger": "Load the TLS certificate pair used by the HTTP server",
              "conditions": [
                "Always during startup"
              ],
              "implementation": "tls.LoadX509KeyPair(s.cfg.TlsCert, s.cfg.TlsKey)"
            }
          ]
        }
      },
      "services": []
    },
    "OpsServiceLifecycle.InitLarkConfig": {
      "infrastructure": {},
      "services": []
    },
    "OpsServiceLifecycle.StartDailyImageReportScheduler": {
      "infrastructure": {
        "scheduler": {
          "conditions": [
            "Startup reached s.startScheduler(ctx)"
          ],
          "operations": [
            {
              "operation": "START_BACKGROUND_WORKER",
              "trigger": "Start the background daily image report scheduler",
              "conditions": [
                "Always after InitLarkConfig"
              ],
              "implementation": "go s.scheduler.StartDailyReportWithLeadership(ctx, scheduleExpr, loc)"
            }
          ]
        }
      },
      "services": []
    },
    "OpsServiceLifecycle.StartupHTTP": {
      "infrastructure": {
        "http_server": {
          "conditions": [
            "registerHandlers(s) completed and TLS certificate loaded"
          ],
          "operations": [
            {
              "operation": "LISTEN_AND_SERVE_TLS",
              "trigger": "Start the HTTPS ops-service listener",
              "conditions": [
                "Always after startup initialization succeeds"
              ],
              "implementation": "s.server.ListenAndServeTLS(\"\", \"\")"
            }
          ]
        }
      },
      "services": []
    },
    "OpsAPI.Health": {
      "infrastructure": {},
      "services": []
    },
    "OpsAPI.UpdateGatewayHPAMinReplicas": {
      "infrastructure": {
        "kubernetes_api": {
          "conditions": [
            "The request body decoded into UpdateMinReplicasRequest successfully"
          ],
          "operations": [
            {
              "operation": "GET",
              "trigger": "Read the target HPA before validation and mutation",
              "conditions": [
                "Always after JSON decoding succeeds"
              ],
              "implementation": "clientSet.AutoscalingV2().HorizontalPodAutoscalers(gatewayHPANamespace).Get(ctx, name, metav1.GetOptions{})"
            },
            {
              "operation": "UPDATE",
              "trigger": "Persist the new minReplicas to the HPA object",
              "conditions": [
                "Only when the target name is not mapped to a Gateway CRD"
              ],
              "implementation": "clientSet.AutoscalingV2().HorizontalPodAutoscalers(gatewayHPANamespace).Update(ctx, hpa, metav1.UpdateOptions{})"
            },
            {
              "operation": "GET/UPDATE",
              "trigger": "Mutate the backing Gateway CRD instead of the HPA",
              "conditions": [
                "Only when name is present in gatewayHPAtoCRDMapping"
              ],
              "implementation": "dynClient.Resource(gatewayCRDGVR).Namespace(gatewayHPANamespace).Get(...); dynClient.Resource(gatewayCRDGVR).Namespace(gatewayHPANamespace).Update(...)"
            }
          ]
        }
      },
      "services": []
    },
    "OpsAPI.ListGatewayHPAMinReplicas": {
      "infrastructure": {
        "kubernetes_api": {
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "LIST",
              "trigger": "List gateway HPAs selected by the control-plane label",
              "conditions": [
                "Always"
              ],
              "implementation": "clientSet.AutoscalingV2().HorizontalPodAutoscalers(gatewayHPANamespace).List(ctx, listOptions)"
            }
          ]
        }
      },
      "services": []
    },
    "OpsAPI.UpdateTiDBAutoscalingThreshold": {
      "infrastructure": {
        "kubernetes_api": {
          "conditions": [
            "Request body decoded successfully and avgValue is in (0, 1]"
          ],
          "operations": [
            {
              "operation": "GET",
              "trigger": "Load the tidb-autoscaling CR in the requested namespace",
              "conditions": [
                "Always after request validation succeeds"
              ],
              "implementation": "dynClient.Resource(tidbAutoscalingGVR).Namespace(namespace).Get(ctx, tidbAutoscalingName, metav1.GetOptions{})"
            },
            {
              "operation": "UPDATE",
              "trigger": "Persist the modified metrics slice back to the tidb-autoscaling CR",
              "conditions": [
                "Only when the requested metric name exists in the metrics list"
              ],
              "implementation": "dynClient.Resource(tidbAutoscalingGVR).Namespace(namespace).Update(ctx, obj, metav1.UpdateOptions{})"
            }
          ]
        }
      },
      "services": []
    },
    "OpsAPI.ListTiDBAutoscalingThreshold": {
      "infrastructure": {
        "kubernetes_api": {
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "LIST",
              "trigger": "List tidb-autoscaling CRs across namespaces",
              "conditions": [
                "Always"
              ],
              "implementation": "dynClient.Resource(tidbAutoscalingGVR).Namespace(\"\").List(ctx, metav1.ListOptions{FieldSelector: fmt.Sprintf(\"metadata.name=%s\", tidbAutoscalingName)})"
            }
          ]
        }
      },
      "services": []
    },
    "OpsAPI.GetComponentImage": {
      "infrastructure": {
        "kubernetes_api": {
          "conditions": [
            "component query parameter is supported"
          ],
          "operations": [
            {
              "operation": "GET",
              "trigger": "Read the image source configured for the requested component",
              "conditions": [
                "When the component uses ConfigMap, CronJob, TiDBCluster CRD, StatefulSet, or Deployment as its source"
              ],
              "implementation": "GetComponentImage(...) -> getImageFromConfigMap/getImageFromCronJob/getImageFromTiDBCluster/getImageFromStatefulSet/getImageFromDeployment"
            }
          ]
        }
      },
      "services": []
    },
    "OpsAPI.TriggerImageReport": {
      "infrastructure": {
        "scheduler": {
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "START_GOROUTINE",
              "trigger": "Run the component image report asynchronously so the HTTP handler can return immediately",
              "conditions": [
                "Always"
              ],
              "implementation": "go s.scheduler.ReportTiDBImageDaily(context.Background())"
            }
          ]
        }
      },
      "services": [
        {
          "name": "self-image-report",
          "target_interface": "ImageReportScheduler.ReportTiDBImageDaily",
          "operation_type": "in_process",
          "conditions": [
            "Always"
          ],
          "operations": [
            {
              "operation": "CALL",
              "trigger": "Delegate the manual trigger endpoint to the same image report worker used by the cron scheduler",
              "conditions": [
                "Always"
              ],
              "implementation": "s.scheduler.ReportTiDBImageDaily(context.Background())"
            }
          ]
        }
      ]
    },
    "ImageReportScheduler.ReportTiDBImageDaily": {
      "infrastructure": {
        "etcd": {
          "conditions": [
            "The background scheduler is running"
          ],
          "operations": [
            {
              "operation": "LOCK",
              "trigger": "Acquire the etcd-based leadership lock before starting the cron scheduler",
              "conditions": [
                "Always before the cron loop begins"
              ],
              "implementation": "AcquireSchedulerLeadership(ctx) -> clientv3.New(...); concurrency.NewSession(...); concurrency.NewMutex(...).Lock(lockCtx)"
            }
          ]
        },
        "kubernetes_api": {
          "conditions": [
            "Leadership acquired and the cron job or manual trigger executed"
          ],
          "operations": [
            {
              "operation": "GET",
              "trigger": "Collect component images from Kubernetes resources across serverless namespaces",
              "conditions": [
                "For each configured component source (ConfigMap, CronJob, TiDBCluster CRD, StatefulSet, or Deployment)"
              ],
              "implementation": "ReportTiDBImageDaily(...) -> GetComponentImage(...)"
            }
          ]
        },
        "http": {
          "conditions": [
            "larkConfig.EnableLarkMsg == true",
            "The report contains at least one line"
          ],
          "operations": [
            {
              "operation": "POST",
              "trigger": "Send the component image report to the configured Lark bot webhook",
              "conditions": [
                "Only when Lark messaging is enabled"
              ],
              "implementation": "SendLarkPost(\"Component Image List\", lines) -> http.NewRequest(http.MethodPost, larkBotWebHook, bytes.NewBuffer(jsonData)); client.Do(req)"
            }
          ]
        }
      },
      "services": []
    }
  }
}
