feat: control plane separation migration - runner dispatch contract and CICD smoke evidence
- Add oto_server_job_client.dart for direct server dispatch - Update runner.proto with new dispatch contract - Update agent_runner and edge_registration_client for control plane separation - Add Go protobuf files for runner service - Update HTTP server with new dispatch endpoints - Add registration and smoke tests - Archive completed task documents
This commit is contained in:
parent
5fd116e447
commit
db0e44ea46
17 changed files with 3180 additions and 136 deletions
|
|
@ -25,33 +25,37 @@ task=m-control-plane-separation-migration/06+05_runner_dispatch_contract, plan=0
|
|||
|
||||
| 항목 | 완료 여부 |
|
||||
|------|---------|
|
||||
| [CICD_RUNNER-1] runner job proto 계약 | [ ] |
|
||||
| [CICD_RUNNER-2] Dart runner reporting client | [ ] |
|
||||
| [CICD_RUNNER-1] runner job proto 계약 | [x] |
|
||||
| [CICD_RUNNER-2] Dart runner reporting client | [x] |
|
||||
|
||||
## 구현 체크리스트
|
||||
|
||||
- [ ] `proto/oto/runner.proto`에 runner job claim/reporting 최소 메시지를 추가하고 `make proto`로 Go/Dart 생성물을 갱신한다.
|
||||
- [ ] Dart runner client에 job claim, execution report, log/artifact report helper를 추가한다.
|
||||
- [ ] `DefaultAgentRunner` 또는 OTO Server session 흐름에 polling/reporting을 주입 가능한 형태로 연결한다.
|
||||
- [ ] fake HTTP server 테스트로 runner가 job을 받고 BuildResult/stepEvents를 OTO Server report payload로 보내는지 검증한다.
|
||||
- [ ] `make proto`, `cd services/core && go test -count=1 ./...`, `cd apps/runner && dart analyze`, agent-smoke Dart 테스트를 통과시킨다.
|
||||
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
|
||||
- [x] `proto/oto/runner.proto`에 runner job claim/reporting 최소 메시지를 추가하고 `make proto`로 Go/Dart 생성물을 갱신한다.
|
||||
- [x] Dart runner client에 job claim, execution report, log/artifact report helper를 추가한다.
|
||||
- [x] `DefaultAgentRunner` 또는 OTO Server session 흐름에 polling/reporting을 주입 가능한 형태로 연결한다.
|
||||
- [x] fake HTTP server 테스트로 runner가 job을 받고 BuildResult/stepEvents를 OTO Server report payload로 보내는지 검증한다.
|
||||
- [x] `make proto`, `cd services/core && go test -count=1 ./...`, `cd apps/runner && dart analyze`, agent-smoke Dart 테스트를 통과시킨다.
|
||||
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
|
||||
|
||||
## 코드리뷰 전용 체크리스트
|
||||
|
||||
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
|
||||
|
||||
- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
|
||||
- [ ] active files를 log로 아카이브하고 PASS이면 `complete.log`를 작성한다.
|
||||
- [ ] PASS이면 active task directory를 archive로 이동한다.
|
||||
- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
|
||||
- [x] active files를 log로 아카이브하고 PASS이면 `complete.log`를 작성한다.
|
||||
- [x] PASS이면 active task directory를 archive로 이동한다.
|
||||
|
||||
## 계획 대비 변경 사항
|
||||
|
||||
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
|
||||
- 계획은 Dart runner client와 proto 중심이었으나, runner-facing HTTP 계약을 실제 Go OTO Server 상태 저장소에 남기기 위해 `services/core/internal/httpserver/server.go`에 runner claim/report/log/artifact route를 함께 추가했다.
|
||||
- `DefaultAgentRunner`에는 실제 polling loop를 고정 구현하지 않고 `runJobs` hook을 추가했다. 현재 runner 실행을 장시간 job loop에 묶지 않으면서 후속 polling/reporting 구현을 주입할 수 있게 하기 위한 최소 연결이다.
|
||||
|
||||
## 주요 설계 결정
|
||||
|
||||
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
|
||||
- `proto/oto/runner.proto`에 `JobClaimRequest/Response`, `ExecutionReportRequest/Response`, `LogAppendRequest/Response`, `ArtifactReportRequest/Response`, `StepEventReport`를 추가하고 `make proto`로 Go/Dart 생성물을 갱신했다.
|
||||
- Go Core는 `/api/v1/runners/{runner_id}/jobs/claim`, `/api/v1/runners/{runner_id}/executions/{execution_id}/report`, `/logs`, `/artifacts`를 `cicdstate.Store`와 연결한다. claim은 queued job을 running execution으로 전환하고, report는 execution/job을 succeeded 또는 failed로 전환한다.
|
||||
- Dart runner에는 `OtoServerJobClient`를 추가해 claim, execution report, log append, artifact report payload를 전송한다. `ExecutionReportRequest` payload는 `BuildResult.toJson()`과 `StepEvent.toJson()`에서 나온 `execution_result`, `step_events`를 포함한다.
|
||||
- `OtoServerRegistrationClient.openSession()`의 OTO Server session은 `OtoServerJobSession.jobs`로 shared HTTP client 기반 job client를 노출한다.
|
||||
|
||||
## 사용자 리뷰 요청
|
||||
|
||||
|
|
@ -78,26 +82,53 @@ _구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후
|
|||
### CICD_RUNNER-1 중간 검증
|
||||
```bash
|
||||
$ make proto
|
||||
(output)
|
||||
mkdir -p services/core/oto
|
||||
protoc -I proto --go_out=services/core --go_opt=paths=source_relative proto/oto/runner.proto
|
||||
mkdir -p apps/runner/lib/oto/agent
|
||||
protoc -I proto --dart_out=apps/runner/lib/oto/agent proto/oto/runner.proto
|
||||
```
|
||||
|
||||
### CICD_RUNNER-2 중간 검증
|
||||
```bash
|
||||
$ cd apps/runner && dart test test/oto_agent_registration_test.dart
|
||||
(output)
|
||||
All tests passed!
|
||||
```
|
||||
|
||||
### 최종 검증
|
||||
```bash
|
||||
$ make proto
|
||||
(output)
|
||||
mkdir -p services/core/oto
|
||||
protoc -I proto --go_out=services/core --go_opt=paths=source_relative proto/oto/runner.proto
|
||||
mkdir -p apps/runner/lib/oto/agent
|
||||
protoc -I proto --dart_out=apps/runner/lib/oto/agent proto/oto/runner.proto
|
||||
|
||||
$ cd services/core && go test -count=1 ./...
|
||||
(output)
|
||||
? github.com/toki/oto/services/core/cmd/oto-core [no test files]
|
||||
ok github.com/toki/oto/services/core/internal/cicdstate 0.002s
|
||||
ok github.com/toki/oto/services/core/internal/httpserver 0.005s
|
||||
ok github.com/toki/oto/services/core/internal/runnerregistry 0.002s
|
||||
? github.com/toki/oto/services/core/oto [no test files]
|
||||
|
||||
$ cd apps/runner && dart analyze
|
||||
(output)
|
||||
Analyzing runner...
|
||||
No issues found!
|
||||
|
||||
$ cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart
|
||||
(output)
|
||||
All tests passed!
|
||||
```
|
||||
|
||||
## 코드리뷰 결과
|
||||
|
||||
### Review 0
|
||||
|
||||
- 종합 판정: PASS
|
||||
- 차원별 평가:
|
||||
- correctness: Pass
|
||||
- completeness: Pass
|
||||
- test coverage: Pass
|
||||
- API contract: Pass
|
||||
- code quality: Pass
|
||||
- plan deviation: Pass
|
||||
- verification trust: Pass
|
||||
- 발견된 문제: 없음
|
||||
- 다음 단계: PASS이므로 active plan/review를 log로 아카이브하고 `complete.log` 작성 후 task directory를 archive로 이동한다.
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# Complete - m-control-plane-separation-migration/06+05_runner_dispatch_contract
|
||||
|
||||
## 완료 일시
|
||||
|
||||
2026-06-06
|
||||
|
||||
## 요약
|
||||
|
||||
runner job claim/report 계약 구현을 1회 리뷰 루프로 완료했다. 최종 판정은 PASS다.
|
||||
|
||||
## 루프 이력
|
||||
|
||||
| Plan | Review | Verdict | 메모 |
|
||||
|------|--------|---------|------|
|
||||
| `plan_cloud_G07_0.log` | `code_review_cloud_G07_0.log` | PASS | proto/Go/Dart runner job 계약, Dart reporting client, Go runner-facing 상태 route, fake server 테스트와 필수 검증 완료 |
|
||||
|
||||
## 구현/정리 내용
|
||||
|
||||
- `proto/oto/runner.proto`에 job claim, execution report, log append, artifact report 메시지를 추가하고 Go/Dart protobuf 생성물을 갱신했다.
|
||||
- Go Core에 runner-facing `/api/v1/runners/{runner_id}/jobs/claim`, execution report, log, artifact route를 추가해 `cicdstate.Store`의 job/execution/log/artifact 상태와 연결했다.
|
||||
- Dart runner에 `OtoServerJobClient`를 추가하고 OTO Server session 및 `DefaultAgentRunner.runJobs` hook으로 주입 가능한 reporting 흐름을 마련했다.
|
||||
- fake HTTP server 기반 Dart 테스트와 Go handler 테스트를 추가해 claim/report payload와 저장 상태 전이를 검증했다.
|
||||
|
||||
## 최종 검증
|
||||
|
||||
- `make proto` - PASS; Go/Dart protobuf 생성 성공.
|
||||
- `cd services/core && go test -count=1 ./...` - PASS; core 전체 package 테스트 통과.
|
||||
- `cd apps/runner && dart analyze` - PASS; `No issues found!`.
|
||||
- `cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart` - PASS; `All tests passed!`.
|
||||
|
||||
## 잔여 Nit
|
||||
|
||||
- 없음
|
||||
|
||||
## 후속 작업
|
||||
|
||||
- 없음
|
||||
|
|
@ -32,32 +32,35 @@ task=m-control-plane-separation-migration/07+05,06_cicd_smoke_evidence, plan=0,
|
|||
|
||||
| 항목 | 완료 여부 |
|
||||
|------|---------|
|
||||
| [CICD_SMOKE-1] OTO Server CI/CD ownership smoke | [ ] |
|
||||
| [CICD_SMOKE-1] OTO Server CI/CD ownership smoke | [x] |
|
||||
|
||||
## 구현 체크리스트
|
||||
|
||||
- [ ] `apps/runner/test/oto_server_connection_smoke_test.dart`에 OTO Server job/execution/log/artifact 상태 round trip smoke를 추가한다.
|
||||
- [ ] smoke가 iop Edge나 iop Control Plane endpoint를 사용하지 않는지 검증한다.
|
||||
- [ ] Go/Dart 필수 검증을 실행하고 실제 출력을 review stub에 기록한다.
|
||||
- [ ] PASS 시 `Roadmap Targets`의 `oto-owns-cicd` 완료 근거로 쓸 수 있도록 검증 내용을 명확히 남긴다.
|
||||
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
|
||||
- [x] `apps/runner/test/oto_server_connection_smoke_test.dart`에 OTO Server job/execution/log/artifact 상태 round trip smoke를 추가한다.
|
||||
- [x] smoke가 iop Edge나 iop Control Plane endpoint를 사용하지 않는지 검증한다.
|
||||
- [x] Go/Dart 필수 검증을 실행하고 실제 출력을 review stub에 기록한다.
|
||||
- [x] PASS 시 `Roadmap Targets`의 `oto-owns-cicd` 완료 근거로 쓸 수 있도록 검증 내용을 명확히 남긴다.
|
||||
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.
|
||||
|
||||
## 코드리뷰 전용 체크리스트
|
||||
|
||||
> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다.
|
||||
|
||||
- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
|
||||
- [ ] active files를 log로 아카이브하고 PASS이면 `complete.log`를 작성한다.
|
||||
- [ ] PASS이면 active task directory를 archive로 이동한다.
|
||||
- [ ] PASS이면 Roadmap Completion 메타데이터에 `oto-owns-cicd`를 포함한다.
|
||||
- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다.
|
||||
- [x] active files를 log로 아카이브하고 PASS이면 `complete.log`를 작성한다.
|
||||
- [x] PASS이면 active task directory를 archive로 이동한다.
|
||||
- [x] PASS이면 Roadmap Completion 메타데이터에 `oto-owns-cicd`를 포함한다.
|
||||
|
||||
## 계획 대비 변경 사항
|
||||
|
||||
_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._
|
||||
- 계획 범위와 동일하게 `apps/runner/test/oto_server_connection_smoke_test.dart`에 통합 smoke만 추가했다.
|
||||
- 06에서 Go handler와 Dart `OtoServerJobClient`가 이미 구현되어 있어 추가 server production 변경은 하지 않았다.
|
||||
|
||||
## 주요 설계 결정
|
||||
|
||||
_구현 에이전트가 주요 설계 결정 사항을 기록한다._
|
||||
- 새 smoke `OTO Server owns job execution logs and artifacts reported by runner`는 실제 `go run ./cmd/oto-core` 프로세스를 띄운 뒤 Dart `OtoServerRegistrationClient`로 runner를 등록하고, 같은 session의 `OtoServerJobSession.jobs`로 job claim, log append, artifact report, execution report를 수행한다.
|
||||
- smoke는 OTO Server의 `/api/v1/jobs`, `/api/v1/runners/{runner_id}/...`, `/api/v1/executions/{execution_id}/...`만 사용한다. iop Edge 또는 iop Control Plane endpoint는 사용하지 않는다.
|
||||
- 완료 증거는 server API 재조회로 확인한다. job/execution `state=succeeded`, `execution_id`, log line, artifact metadata가 OTO Server에 남아야 테스트가 통과한다.
|
||||
|
||||
## 사용자 리뷰 요청
|
||||
|
||||
|
|
@ -84,18 +87,38 @@ _구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후
|
|||
### CICD_SMOKE-1 중간 검증
|
||||
```bash
|
||||
$ cd apps/runner && dart test test/oto_server_connection_smoke_test.dart
|
||||
(output)
|
||||
All tests passed!
|
||||
```
|
||||
|
||||
### 최종 검증
|
||||
```bash
|
||||
$ cd services/core && go test -count=1 ./...
|
||||
(output)
|
||||
? github.com/toki/oto/services/core/cmd/oto-core [no test files]
|
||||
ok github.com/toki/oto/services/core/internal/cicdstate 0.002s
|
||||
ok github.com/toki/oto/services/core/internal/httpserver 0.005s
|
||||
ok github.com/toki/oto/services/core/internal/runnerregistry 0.003s
|
||||
? github.com/toki/oto/services/core/oto [no test files]
|
||||
|
||||
$ cd apps/runner && dart analyze
|
||||
(output)
|
||||
Analyzing runner...
|
||||
No issues found!
|
||||
|
||||
$ cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart
|
||||
(output)
|
||||
All tests passed!
|
||||
```
|
||||
|
||||
## 코드리뷰 결과
|
||||
|
||||
### Review 0
|
||||
|
||||
- 종합 판정: PASS
|
||||
- 차원별 평가:
|
||||
- correctness: Pass
|
||||
- completeness: Pass
|
||||
- test coverage: Pass
|
||||
- API contract: Pass
|
||||
- code quality: Pass
|
||||
- plan deviation: Pass
|
||||
- verification trust: Pass
|
||||
- 발견된 문제: 없음
|
||||
- 다음 단계: PASS이므로 active plan/review를 log로 아카이브하고 `complete.log` 작성 후 task directory를 archive로 이동한다. `complete.log`의 Roadmap Completion에는 `oto-owns-cicd`를 포함한다.
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
# Complete - m-control-plane-separation-migration/07+05,06_cicd_smoke_evidence
|
||||
|
||||
## 완료 일시
|
||||
|
||||
2026-06-06
|
||||
|
||||
## 요약
|
||||
|
||||
OTO Server CI/CD ownership smoke 증거를 1회 리뷰 루프로 완료했다. 최종 판정은 PASS다.
|
||||
|
||||
## 루프 이력
|
||||
|
||||
| Plan | Review | Verdict | 메모 |
|
||||
|------|--------|---------|------|
|
||||
| `plan_cloud_G07_0.log` | `code_review_cloud_G07_0.log` | PASS | 실제 Go OTO Server process와 Dart runner session을 통한 job/execution/log/artifact round trip smoke 검증 완료 |
|
||||
|
||||
## 구현/정리 내용
|
||||
|
||||
- `apps/runner/test/oto_server_connection_smoke_test.dart`에 `OTO Server owns job execution logs and artifacts reported by runner` smoke를 추가했다.
|
||||
- smoke는 Go OTO Server 프로세스를 띄우고 Dart runner를 등록한 뒤 `OtoServerJobSession.jobs`로 job claim, log append, artifact report, execution report를 수행한다.
|
||||
- smoke는 OTO Server API 재조회로 job/execution `succeeded` 상태, execution id, log line, artifact metadata가 서버에 남는지 검증한다.
|
||||
- smoke는 iop Edge나 iop Control Plane endpoint를 사용하지 않는다.
|
||||
|
||||
## 최종 검증
|
||||
|
||||
- `cd apps/runner && dart test test/oto_server_connection_smoke_test.dart` - PASS; `All tests passed!`.
|
||||
- `cd services/core && go test -count=1 ./...` - PASS; core 전체 package 테스트 통과.
|
||||
- `cd apps/runner && dart analyze` - PASS; `No issues found!`.
|
||||
- `cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart` - PASS; `All tests passed!`.
|
||||
|
||||
## Roadmap Completion
|
||||
|
||||
- Milestone: `agent-roadmap/phase/independent-control-plane/milestones/control-plane-separation-migration.md`
|
||||
- Completed task ids:
|
||||
- `oto-owns-cicd`: PASS; evidence=`plan_cloud_G07_0.log`, `code_review_cloud_G07_0.log`; verification=`cd apps/runner && dart test test/oto_server_connection_smoke_test.dart`, `cd services/core && go test -count=1 ./...`, `cd apps/runner && dart analyze`, `cd apps/runner && dart test test/oto_agent_migration_plan_test.dart test/oto_agent_bootstrap_script_test.dart test/oto_agent_cli_test.dart test/oto_agent_config_test.dart test/oto_agent_registration_test.dart test/oto_server_connection_smoke_test.dart`
|
||||
- Not completed task ids: 없음
|
||||
|
||||
## 잔여 Nit
|
||||
|
||||
- 없음
|
||||
|
||||
## 후속 작업
|
||||
|
||||
- 없음
|
||||
|
|
@ -20,14 +20,17 @@ class DefaultAgentRunner implements AgentRunner {
|
|||
final RegistrationClient _client;
|
||||
final void Function(String)? _onLog;
|
||||
final Future<void> Function()? _waitForShutdown;
|
||||
final Future<void> Function(AgentConfig, EdgeAgentSession)? _runJobs;
|
||||
|
||||
DefaultAgentRunner({
|
||||
RegistrationClient? client,
|
||||
void Function(String)? onLog,
|
||||
Future<void> Function()? waitForShutdown,
|
||||
Future<void> Function(AgentConfig, EdgeAgentSession)? runJobs,
|
||||
}) : _client = client ?? OtoServerRegistrationClient(),
|
||||
_onLog = onLog,
|
||||
_waitForShutdown = waitForShutdown;
|
||||
_waitForShutdown = waitForShutdown,
|
||||
_runJobs = runJobs;
|
||||
|
||||
@override
|
||||
Future<void> run(AgentConfig config) async {
|
||||
|
|
@ -57,6 +60,10 @@ class DefaultAgentRunner implements AgentRunner {
|
|||
_log('Alias: ${result.alias}');
|
||||
}
|
||||
|
||||
if (_runJobs != null) {
|
||||
await _runJobs(config, session);
|
||||
}
|
||||
|
||||
_log('Agent connected. Waiting for shutdown signal...');
|
||||
await _awaitShutdown();
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:proto_socket/proto_socket.dart';
|
|||
import 'package:oto/oto/agent/agent_config.dart';
|
||||
import 'package:oto/oto/agent/iop/runtime.pb.dart' as iop;
|
||||
import 'package:oto/oto/agent/oto/runner.pb.dart' as oto;
|
||||
import 'package:oto/oto/agent/oto_server_job_client.dart';
|
||||
import 'package:oto/oto/commands/command.dart';
|
||||
import 'package:oto/oto/commands/command_registry.dart';
|
||||
|
||||
|
|
@ -168,6 +169,10 @@ abstract class EdgeAgentSession {
|
|||
Future<void> close();
|
||||
}
|
||||
|
||||
abstract class OtoServerJobSession implements EdgeAgentSession {
|
||||
OtoServerJobClient get jobs;
|
||||
}
|
||||
|
||||
class _OtoEdgeAgentSession implements EdgeAgentSession {
|
||||
final _OtoIopClient _client;
|
||||
|
||||
|
|
@ -269,7 +274,9 @@ class OtoServerRegistrationClient extends RegistrationClient {
|
|||
if (uri.host.isEmpty) {
|
||||
throw FormatException('Invalid server url: "$serverUrl"');
|
||||
}
|
||||
return uri.replace(path: _joinPath(uri.path, '/api/v1/runners/$runnerId/heartbeat'));
|
||||
return uri.replace(
|
||||
path: _joinPath(uri.path, '/api/v1/runners/$runnerId/heartbeat'),
|
||||
);
|
||||
}
|
||||
|
||||
static Uri disconnectUri(String serverUrl, String runnerId) {
|
||||
|
|
@ -281,7 +288,9 @@ class OtoServerRegistrationClient extends RegistrationClient {
|
|||
if (uri.host.isEmpty) {
|
||||
throw FormatException('Invalid server url: "$serverUrl"');
|
||||
}
|
||||
return uri.replace(path: _joinPath(uri.path, '/api/v1/runners/$runnerId/disconnect'));
|
||||
return uri.replace(
|
||||
path: _joinPath(uri.path, '/api/v1/runners/$runnerId/disconnect'),
|
||||
);
|
||||
}
|
||||
|
||||
static String _joinPath(String basePath, String endpointPath) {
|
||||
|
|
@ -313,7 +322,7 @@ class OtoServerRegistrationClient extends RegistrationClient {
|
|||
}
|
||||
}
|
||||
|
||||
class _OtoServerAgentSession implements EdgeAgentSession {
|
||||
class _OtoServerAgentSession implements OtoServerJobSession {
|
||||
final http.Client _client;
|
||||
final bool _shouldCloseClient;
|
||||
final String _serverUrl;
|
||||
|
|
@ -324,6 +333,9 @@ class _OtoServerAgentSession implements EdgeAgentSession {
|
|||
@override
|
||||
final RegistrationResult result;
|
||||
|
||||
@override
|
||||
late final OtoServerJobClient jobs;
|
||||
|
||||
_OtoServerAgentSession(
|
||||
this.result,
|
||||
this._client,
|
||||
|
|
@ -332,8 +344,16 @@ class _OtoServerAgentSession implements EdgeAgentSession {
|
|||
this._runnerId, {
|
||||
required Duration heartbeatInterval,
|
||||
}) {
|
||||
jobs = OtoServerJobClient(
|
||||
serverUrl: _serverUrl,
|
||||
runnerId: _runnerId,
|
||||
client: _client,
|
||||
);
|
||||
if (result.accepted) {
|
||||
_heartbeatTimer = Timer.periodic(heartbeatInterval, (_) => _sendHeartbeat());
|
||||
_heartbeatTimer = Timer.periodic(
|
||||
heartbeatInterval,
|
||||
(_) => _sendHeartbeat(),
|
||||
);
|
||||
scheduleMicrotask(() => _sendHeartbeat());
|
||||
}
|
||||
}
|
||||
|
|
@ -341,16 +361,17 @@ class _OtoServerAgentSession implements EdgeAgentSession {
|
|||
Future<void> _sendHeartbeat() async {
|
||||
if (_closed) return;
|
||||
try {
|
||||
final uri = OtoServerRegistrationClient.heartbeatUri(_serverUrl, _runnerId);
|
||||
final uri = OtoServerRegistrationClient.heartbeatUri(
|
||||
_serverUrl,
|
||||
_runnerId,
|
||||
);
|
||||
final body = jsonEncode({
|
||||
'runner_id': _runnerId,
|
||||
'status': 1, // HEARTBEAT_STATUS_HEALTHY
|
||||
});
|
||||
await _client.post(
|
||||
uri,
|
||||
headers: {'content-type': 'application/json'},
|
||||
body: body,
|
||||
).timeout(const Duration(seconds: 5));
|
||||
await _client
|
||||
.post(uri, headers: {'content-type': 'application/json'}, body: body)
|
||||
.timeout(const Duration(seconds: 5));
|
||||
} catch (_) {
|
||||
// Ignore background errors
|
||||
}
|
||||
|
|
@ -366,11 +387,13 @@ class _OtoServerAgentSession implements EdgeAgentSession {
|
|||
|
||||
if (result.accepted) {
|
||||
try {
|
||||
final uri = OtoServerRegistrationClient.disconnectUri(_serverUrl, _runnerId);
|
||||
await _client.post(
|
||||
uri,
|
||||
headers: {'content-type': 'application/json'},
|
||||
).timeout(const Duration(seconds: 5));
|
||||
final uri = OtoServerRegistrationClient.disconnectUri(
|
||||
_serverUrl,
|
||||
_runnerId,
|
||||
);
|
||||
await _client
|
||||
.post(uri, headers: {'content-type': 'application/json'})
|
||||
.timeout(const Duration(seconds: 5));
|
||||
} catch (_) {
|
||||
// Ignore disconnect errors
|
||||
}
|
||||
|
|
|
|||
|
|
@ -602,6 +602,873 @@ class BootstrapCommandResponse extends $pb.GeneratedMessage {
|
|||
void clearBootstrapCommand() => $_clearField(1);
|
||||
}
|
||||
|
||||
class JobClaimRequest extends $pb.GeneratedMessage {
|
||||
factory JobClaimRequest({
|
||||
$core.String? runnerId,
|
||||
$core.String? jobId,
|
||||
$core.String? executionId,
|
||||
}) {
|
||||
final result = create();
|
||||
if (runnerId != null) result.runnerId = runnerId;
|
||||
if (jobId != null) result.jobId = jobId;
|
||||
if (executionId != null) result.executionId = executionId;
|
||||
return result;
|
||||
}
|
||||
|
||||
JobClaimRequest._();
|
||||
|
||||
factory JobClaimRequest.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory JobClaimRequest.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'JobClaimRequest',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
|
||||
createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'runnerId')
|
||||
..aOS(2, _omitFieldNames ? '' : 'jobId')
|
||||
..aOS(3, _omitFieldNames ? '' : 'executionId')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
JobClaimRequest clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
JobClaimRequest copyWith(void Function(JobClaimRequest) updates) =>
|
||||
super.copyWith((message) => updates(message as JobClaimRequest))
|
||||
as JobClaimRequest;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static JobClaimRequest create() => JobClaimRequest._();
|
||||
@$core.override
|
||||
JobClaimRequest createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static JobClaimRequest getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<JobClaimRequest>(create);
|
||||
static JobClaimRequest? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get runnerId => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set runnerId($core.String value) => $_setString(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasRunnerId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearRunnerId() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get jobId => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set jobId($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasJobId() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearJobId() => $_clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get executionId => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set executionId($core.String value) => $_setString(2, value);
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasExecutionId() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearExecutionId() => $_clearField(3);
|
||||
}
|
||||
|
||||
class JobClaimResponse extends $pb.GeneratedMessage {
|
||||
factory JobClaimResponse({
|
||||
$core.bool? accepted,
|
||||
$core.String? errorMessage,
|
||||
$core.String? jobId,
|
||||
$core.String? executionId,
|
||||
$core.String? state,
|
||||
$core.String? runnerId,
|
||||
}) {
|
||||
final result = create();
|
||||
if (accepted != null) result.accepted = accepted;
|
||||
if (errorMessage != null) result.errorMessage = errorMessage;
|
||||
if (jobId != null) result.jobId = jobId;
|
||||
if (executionId != null) result.executionId = executionId;
|
||||
if (state != null) result.state = state;
|
||||
if (runnerId != null) result.runnerId = runnerId;
|
||||
return result;
|
||||
}
|
||||
|
||||
JobClaimResponse._();
|
||||
|
||||
factory JobClaimResponse.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory JobClaimResponse.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'JobClaimResponse',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
|
||||
createEmptyInstance: create)
|
||||
..aOB(1, _omitFieldNames ? '' : 'accepted')
|
||||
..aOS(2, _omitFieldNames ? '' : 'errorMessage')
|
||||
..aOS(3, _omitFieldNames ? '' : 'jobId')
|
||||
..aOS(4, _omitFieldNames ? '' : 'executionId')
|
||||
..aOS(5, _omitFieldNames ? '' : 'state')
|
||||
..aOS(6, _omitFieldNames ? '' : 'runnerId')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
JobClaimResponse clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
JobClaimResponse copyWith(void Function(JobClaimResponse) updates) =>
|
||||
super.copyWith((message) => updates(message as JobClaimResponse))
|
||||
as JobClaimResponse;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static JobClaimResponse create() => JobClaimResponse._();
|
||||
@$core.override
|
||||
JobClaimResponse createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static JobClaimResponse getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<JobClaimResponse>(create);
|
||||
static JobClaimResponse? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool get accepted => $_getBF(0);
|
||||
@$pb.TagNumber(1)
|
||||
set accepted($core.bool value) => $_setBool(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasAccepted() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearAccepted() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get errorMessage => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set errorMessage($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasErrorMessage() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearErrorMessage() => $_clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get jobId => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set jobId($core.String value) => $_setString(2, value);
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasJobId() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearJobId() => $_clearField(3);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$core.String get executionId => $_getSZ(3);
|
||||
@$pb.TagNumber(4)
|
||||
set executionId($core.String value) => $_setString(3, value);
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasExecutionId() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearExecutionId() => $_clearField(4);
|
||||
|
||||
@$pb.TagNumber(5)
|
||||
$core.String get state => $_getSZ(4);
|
||||
@$pb.TagNumber(5)
|
||||
set state($core.String value) => $_setString(4, value);
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasState() => $_has(4);
|
||||
@$pb.TagNumber(5)
|
||||
void clearState() => $_clearField(5);
|
||||
|
||||
@$pb.TagNumber(6)
|
||||
$core.String get runnerId => $_getSZ(5);
|
||||
@$pb.TagNumber(6)
|
||||
set runnerId($core.String value) => $_setString(5, value);
|
||||
@$pb.TagNumber(6)
|
||||
$core.bool hasRunnerId() => $_has(5);
|
||||
@$pb.TagNumber(6)
|
||||
void clearRunnerId() => $_clearField(6);
|
||||
}
|
||||
|
||||
class StepEventReport extends $pb.GeneratedMessage {
|
||||
factory StepEventReport({
|
||||
$core.int? stepId,
|
||||
$core.int? workflowIndex,
|
||||
$core.String? stepType,
|
||||
$core.String? event,
|
||||
$core.String? timestamp,
|
||||
$core.String? commandId,
|
||||
$core.String? commandType,
|
||||
$core.Iterable<$core.MapEntry<$core.String, $core.String>>? error,
|
||||
}) {
|
||||
final result = create();
|
||||
if (stepId != null) result.stepId = stepId;
|
||||
if (workflowIndex != null) result.workflowIndex = workflowIndex;
|
||||
if (stepType != null) result.stepType = stepType;
|
||||
if (event != null) result.event = event;
|
||||
if (timestamp != null) result.timestamp = timestamp;
|
||||
if (commandId != null) result.commandId = commandId;
|
||||
if (commandType != null) result.commandType = commandType;
|
||||
if (error != null) result.error.addEntries(error);
|
||||
return result;
|
||||
}
|
||||
|
||||
StepEventReport._();
|
||||
|
||||
factory StepEventReport.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory StepEventReport.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'StepEventReport',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
|
||||
createEmptyInstance: create)
|
||||
..aI(1, _omitFieldNames ? '' : 'stepId')
|
||||
..aI(2, _omitFieldNames ? '' : 'workflowIndex')
|
||||
..aOS(3, _omitFieldNames ? '' : 'stepType')
|
||||
..aOS(4, _omitFieldNames ? '' : 'event')
|
||||
..aOS(5, _omitFieldNames ? '' : 'timestamp')
|
||||
..aOS(6, _omitFieldNames ? '' : 'commandId')
|
||||
..aOS(7, _omitFieldNames ? '' : 'commandType')
|
||||
..m<$core.String, $core.String>(8, _omitFieldNames ? '' : 'error',
|
||||
entryClassName: 'StepEventReport.ErrorEntry',
|
||||
keyFieldType: $pb.PbFieldType.OS,
|
||||
valueFieldType: $pb.PbFieldType.OS,
|
||||
packageName: const $pb.PackageName('oto.runner.v1'))
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
StepEventReport clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
StepEventReport copyWith(void Function(StepEventReport) updates) =>
|
||||
super.copyWith((message) => updates(message as StepEventReport))
|
||||
as StepEventReport;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static StepEventReport create() => StepEventReport._();
|
||||
@$core.override
|
||||
StepEventReport createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static StepEventReport getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<StepEventReport>(create);
|
||||
static StepEventReport? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.int get stepId => $_getIZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set stepId($core.int value) => $_setSignedInt32(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasStepId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearStepId() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.int get workflowIndex => $_getIZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set workflowIndex($core.int value) => $_setSignedInt32(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasWorkflowIndex() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearWorkflowIndex() => $_clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get stepType => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set stepType($core.String value) => $_setString(2, value);
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasStepType() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearStepType() => $_clearField(3);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$core.String get event => $_getSZ(3);
|
||||
@$pb.TagNumber(4)
|
||||
set event($core.String value) => $_setString(3, value);
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasEvent() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearEvent() => $_clearField(4);
|
||||
|
||||
@$pb.TagNumber(5)
|
||||
$core.String get timestamp => $_getSZ(4);
|
||||
@$pb.TagNumber(5)
|
||||
set timestamp($core.String value) => $_setString(4, value);
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasTimestamp() => $_has(4);
|
||||
@$pb.TagNumber(5)
|
||||
void clearTimestamp() => $_clearField(5);
|
||||
|
||||
@$pb.TagNumber(6)
|
||||
$core.String get commandId => $_getSZ(5);
|
||||
@$pb.TagNumber(6)
|
||||
set commandId($core.String value) => $_setString(5, value);
|
||||
@$pb.TagNumber(6)
|
||||
$core.bool hasCommandId() => $_has(5);
|
||||
@$pb.TagNumber(6)
|
||||
void clearCommandId() => $_clearField(6);
|
||||
|
||||
@$pb.TagNumber(7)
|
||||
$core.String get commandType => $_getSZ(6);
|
||||
@$pb.TagNumber(7)
|
||||
set commandType($core.String value) => $_setString(6, value);
|
||||
@$pb.TagNumber(7)
|
||||
$core.bool hasCommandType() => $_has(6);
|
||||
@$pb.TagNumber(7)
|
||||
void clearCommandType() => $_clearField(7);
|
||||
|
||||
@$pb.TagNumber(8)
|
||||
$pb.PbMap<$core.String, $core.String> get error => $_getMap(7);
|
||||
}
|
||||
|
||||
class ExecutionReportRequest extends $pb.GeneratedMessage {
|
||||
factory ExecutionReportRequest({
|
||||
$core.String? runnerId,
|
||||
$core.String? jobId,
|
||||
$core.String? executionId,
|
||||
$core.bool? success,
|
||||
$core.int? exitCode,
|
||||
$core.String? message,
|
||||
$core.Iterable<StepEventReport>? stepEvents,
|
||||
}) {
|
||||
final result = create();
|
||||
if (runnerId != null) result.runnerId = runnerId;
|
||||
if (jobId != null) result.jobId = jobId;
|
||||
if (executionId != null) result.executionId = executionId;
|
||||
if (success != null) result.success = success;
|
||||
if (exitCode != null) result.exitCode = exitCode;
|
||||
if (message != null) result.message = message;
|
||||
if (stepEvents != null) result.stepEvents.addAll(stepEvents);
|
||||
return result;
|
||||
}
|
||||
|
||||
ExecutionReportRequest._();
|
||||
|
||||
factory ExecutionReportRequest.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory ExecutionReportRequest.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'ExecutionReportRequest',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
|
||||
createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'runnerId')
|
||||
..aOS(2, _omitFieldNames ? '' : 'jobId')
|
||||
..aOS(3, _omitFieldNames ? '' : 'executionId')
|
||||
..aOB(4, _omitFieldNames ? '' : 'success')
|
||||
..aI(5, _omitFieldNames ? '' : 'exitCode')
|
||||
..aOS(6, _omitFieldNames ? '' : 'message')
|
||||
..pPM<StepEventReport>(7, _omitFieldNames ? '' : 'stepEvents',
|
||||
subBuilder: StepEventReport.create)
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ExecutionReportRequest clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ExecutionReportRequest copyWith(
|
||||
void Function(ExecutionReportRequest) updates) =>
|
||||
super.copyWith((message) => updates(message as ExecutionReportRequest))
|
||||
as ExecutionReportRequest;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ExecutionReportRequest create() => ExecutionReportRequest._();
|
||||
@$core.override
|
||||
ExecutionReportRequest createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ExecutionReportRequest getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<ExecutionReportRequest>(create);
|
||||
static ExecutionReportRequest? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get runnerId => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set runnerId($core.String value) => $_setString(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasRunnerId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearRunnerId() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get jobId => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set jobId($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasJobId() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearJobId() => $_clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get executionId => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set executionId($core.String value) => $_setString(2, value);
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasExecutionId() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearExecutionId() => $_clearField(3);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool get success => $_getBF(3);
|
||||
@$pb.TagNumber(4)
|
||||
set success($core.bool value) => $_setBool(3, value);
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasSuccess() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearSuccess() => $_clearField(4);
|
||||
|
||||
@$pb.TagNumber(5)
|
||||
$core.int get exitCode => $_getIZ(4);
|
||||
@$pb.TagNumber(5)
|
||||
set exitCode($core.int value) => $_setSignedInt32(4, value);
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasExitCode() => $_has(4);
|
||||
@$pb.TagNumber(5)
|
||||
void clearExitCode() => $_clearField(5);
|
||||
|
||||
@$pb.TagNumber(6)
|
||||
$core.String get message => $_getSZ(5);
|
||||
@$pb.TagNumber(6)
|
||||
set message($core.String value) => $_setString(5, value);
|
||||
@$pb.TagNumber(6)
|
||||
$core.bool hasMessage() => $_has(5);
|
||||
@$pb.TagNumber(6)
|
||||
void clearMessage() => $_clearField(6);
|
||||
|
||||
@$pb.TagNumber(7)
|
||||
$pb.PbList<StepEventReport> get stepEvents => $_getList(6);
|
||||
}
|
||||
|
||||
class ExecutionReportResponse extends $pb.GeneratedMessage {
|
||||
factory ExecutionReportResponse({
|
||||
$core.bool? accepted,
|
||||
$core.String? errorMessage,
|
||||
$core.String? jobId,
|
||||
$core.String? executionId,
|
||||
$core.String? state,
|
||||
$core.String? runnerId,
|
||||
}) {
|
||||
final result = create();
|
||||
if (accepted != null) result.accepted = accepted;
|
||||
if (errorMessage != null) result.errorMessage = errorMessage;
|
||||
if (jobId != null) result.jobId = jobId;
|
||||
if (executionId != null) result.executionId = executionId;
|
||||
if (state != null) result.state = state;
|
||||
if (runnerId != null) result.runnerId = runnerId;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExecutionReportResponse._();
|
||||
|
||||
factory ExecutionReportResponse.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory ExecutionReportResponse.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'ExecutionReportResponse',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
|
||||
createEmptyInstance: create)
|
||||
..aOB(1, _omitFieldNames ? '' : 'accepted')
|
||||
..aOS(2, _omitFieldNames ? '' : 'errorMessage')
|
||||
..aOS(3, _omitFieldNames ? '' : 'jobId')
|
||||
..aOS(4, _omitFieldNames ? '' : 'executionId')
|
||||
..aOS(5, _omitFieldNames ? '' : 'state')
|
||||
..aOS(6, _omitFieldNames ? '' : 'runnerId')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ExecutionReportResponse clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ExecutionReportResponse copyWith(
|
||||
void Function(ExecutionReportResponse) updates) =>
|
||||
super.copyWith((message) => updates(message as ExecutionReportResponse))
|
||||
as ExecutionReportResponse;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ExecutionReportResponse create() => ExecutionReportResponse._();
|
||||
@$core.override
|
||||
ExecutionReportResponse createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ExecutionReportResponse getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<ExecutionReportResponse>(create);
|
||||
static ExecutionReportResponse? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool get accepted => $_getBF(0);
|
||||
@$pb.TagNumber(1)
|
||||
set accepted($core.bool value) => $_setBool(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasAccepted() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearAccepted() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get errorMessage => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set errorMessage($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasErrorMessage() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearErrorMessage() => $_clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get jobId => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set jobId($core.String value) => $_setString(2, value);
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasJobId() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearJobId() => $_clearField(3);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$core.String get executionId => $_getSZ(3);
|
||||
@$pb.TagNumber(4)
|
||||
set executionId($core.String value) => $_setString(3, value);
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasExecutionId() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearExecutionId() => $_clearField(4);
|
||||
|
||||
@$pb.TagNumber(5)
|
||||
$core.String get state => $_getSZ(4);
|
||||
@$pb.TagNumber(5)
|
||||
set state($core.String value) => $_setString(4, value);
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasState() => $_has(4);
|
||||
@$pb.TagNumber(5)
|
||||
void clearState() => $_clearField(5);
|
||||
|
||||
@$pb.TagNumber(6)
|
||||
$core.String get runnerId => $_getSZ(5);
|
||||
@$pb.TagNumber(6)
|
||||
set runnerId($core.String value) => $_setString(5, value);
|
||||
@$pb.TagNumber(6)
|
||||
$core.bool hasRunnerId() => $_has(5);
|
||||
@$pb.TagNumber(6)
|
||||
void clearRunnerId() => $_clearField(6);
|
||||
}
|
||||
|
||||
class LogAppendRequest extends $pb.GeneratedMessage {
|
||||
factory LogAppendRequest({
|
||||
$core.String? runnerId,
|
||||
$core.String? executionId,
|
||||
$core.String? line,
|
||||
}) {
|
||||
final result = create();
|
||||
if (runnerId != null) result.runnerId = runnerId;
|
||||
if (executionId != null) result.executionId = executionId;
|
||||
if (line != null) result.line = line;
|
||||
return result;
|
||||
}
|
||||
|
||||
LogAppendRequest._();
|
||||
|
||||
factory LogAppendRequest.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory LogAppendRequest.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'LogAppendRequest',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
|
||||
createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'runnerId')
|
||||
..aOS(2, _omitFieldNames ? '' : 'executionId')
|
||||
..aOS(3, _omitFieldNames ? '' : 'line')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
LogAppendRequest clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
LogAppendRequest copyWith(void Function(LogAppendRequest) updates) =>
|
||||
super.copyWith((message) => updates(message as LogAppendRequest))
|
||||
as LogAppendRequest;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static LogAppendRequest create() => LogAppendRequest._();
|
||||
@$core.override
|
||||
LogAppendRequest createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static LogAppendRequest getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<LogAppendRequest>(create);
|
||||
static LogAppendRequest? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get runnerId => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set runnerId($core.String value) => $_setString(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasRunnerId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearRunnerId() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get executionId => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set executionId($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasExecutionId() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearExecutionId() => $_clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get line => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set line($core.String value) => $_setString(2, value);
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasLine() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearLine() => $_clearField(3);
|
||||
}
|
||||
|
||||
class LogAppendResponse extends $pb.GeneratedMessage {
|
||||
factory LogAppendResponse({
|
||||
$core.bool? accepted,
|
||||
$core.String? errorMessage,
|
||||
}) {
|
||||
final result = create();
|
||||
if (accepted != null) result.accepted = accepted;
|
||||
if (errorMessage != null) result.errorMessage = errorMessage;
|
||||
return result;
|
||||
}
|
||||
|
||||
LogAppendResponse._();
|
||||
|
||||
factory LogAppendResponse.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory LogAppendResponse.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'LogAppendResponse',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
|
||||
createEmptyInstance: create)
|
||||
..aOB(1, _omitFieldNames ? '' : 'accepted')
|
||||
..aOS(2, _omitFieldNames ? '' : 'errorMessage')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
LogAppendResponse clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
LogAppendResponse copyWith(void Function(LogAppendResponse) updates) =>
|
||||
super.copyWith((message) => updates(message as LogAppendResponse))
|
||||
as LogAppendResponse;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static LogAppendResponse create() => LogAppendResponse._();
|
||||
@$core.override
|
||||
LogAppendResponse createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static LogAppendResponse getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<LogAppendResponse>(create);
|
||||
static LogAppendResponse? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool get accepted => $_getBF(0);
|
||||
@$pb.TagNumber(1)
|
||||
set accepted($core.bool value) => $_setBool(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasAccepted() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearAccepted() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get errorMessage => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set errorMessage($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasErrorMessage() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearErrorMessage() => $_clearField(2);
|
||||
}
|
||||
|
||||
class ArtifactReportRequest extends $pb.GeneratedMessage {
|
||||
factory ArtifactReportRequest({
|
||||
$core.String? runnerId,
|
||||
$core.String? executionId,
|
||||
$core.String? name,
|
||||
$core.String? path,
|
||||
}) {
|
||||
final result = create();
|
||||
if (runnerId != null) result.runnerId = runnerId;
|
||||
if (executionId != null) result.executionId = executionId;
|
||||
if (name != null) result.name = name;
|
||||
if (path != null) result.path = path;
|
||||
return result;
|
||||
}
|
||||
|
||||
ArtifactReportRequest._();
|
||||
|
||||
factory ArtifactReportRequest.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory ArtifactReportRequest.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'ArtifactReportRequest',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
|
||||
createEmptyInstance: create)
|
||||
..aOS(1, _omitFieldNames ? '' : 'runnerId')
|
||||
..aOS(2, _omitFieldNames ? '' : 'executionId')
|
||||
..aOS(3, _omitFieldNames ? '' : 'name')
|
||||
..aOS(4, _omitFieldNames ? '' : 'path')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ArtifactReportRequest clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ArtifactReportRequest copyWith(
|
||||
void Function(ArtifactReportRequest) updates) =>
|
||||
super.copyWith((message) => updates(message as ArtifactReportRequest))
|
||||
as ArtifactReportRequest;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ArtifactReportRequest create() => ArtifactReportRequest._();
|
||||
@$core.override
|
||||
ArtifactReportRequest createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ArtifactReportRequest getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<ArtifactReportRequest>(create);
|
||||
static ArtifactReportRequest? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.String get runnerId => $_getSZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set runnerId($core.String value) => $_setString(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasRunnerId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearRunnerId() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get executionId => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set executionId($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasExecutionId() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearExecutionId() => $_clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.String get name => $_getSZ(2);
|
||||
@$pb.TagNumber(3)
|
||||
set name($core.String value) => $_setString(2, value);
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasName() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearName() => $_clearField(3);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$core.String get path => $_getSZ(3);
|
||||
@$pb.TagNumber(4)
|
||||
set path($core.String value) => $_setString(3, value);
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasPath() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearPath() => $_clearField(4);
|
||||
}
|
||||
|
||||
class ArtifactReportResponse extends $pb.GeneratedMessage {
|
||||
factory ArtifactReportResponse({
|
||||
$core.bool? accepted,
|
||||
$core.String? errorMessage,
|
||||
}) {
|
||||
final result = create();
|
||||
if (accepted != null) result.accepted = accepted;
|
||||
if (errorMessage != null) result.errorMessage = errorMessage;
|
||||
return result;
|
||||
}
|
||||
|
||||
ArtifactReportResponse._();
|
||||
|
||||
factory ArtifactReportResponse.fromBuffer($core.List<$core.int> data,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromBuffer(data, registry);
|
||||
factory ArtifactReportResponse.fromJson($core.String json,
|
||||
[$pb.ExtensionRegistry registry = $pb.ExtensionRegistry.EMPTY]) =>
|
||||
create()..mergeFromJson(json, registry);
|
||||
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(
|
||||
_omitMessageNames ? '' : 'ArtifactReportResponse',
|
||||
package: const $pb.PackageName(_omitMessageNames ? '' : 'oto.runner.v1'),
|
||||
createEmptyInstance: create)
|
||||
..aOB(1, _omitFieldNames ? '' : 'accepted')
|
||||
..aOS(2, _omitFieldNames ? '' : 'errorMessage')
|
||||
..hasRequiredFields = false;
|
||||
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ArtifactReportResponse clone() => deepCopy();
|
||||
@$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
|
||||
ArtifactReportResponse copyWith(
|
||||
void Function(ArtifactReportResponse) updates) =>
|
||||
super.copyWith((message) => updates(message as ArtifactReportResponse))
|
||||
as ArtifactReportResponse;
|
||||
|
||||
@$core.override
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ArtifactReportResponse create() => ArtifactReportResponse._();
|
||||
@$core.override
|
||||
ArtifactReportResponse createEmptyInstance() => create();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static ArtifactReportResponse getDefault() => _defaultInstance ??=
|
||||
$pb.GeneratedMessage.$_defaultFor<ArtifactReportResponse>(create);
|
||||
static ArtifactReportResponse? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool get accepted => $_getBF(0);
|
||||
@$pb.TagNumber(1)
|
||||
set accepted($core.bool value) => $_setBool(0, value);
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasAccepted() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearAccepted() => $_clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.String get errorMessage => $_getSZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set errorMessage($core.String value) => $_setString(1, value);
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasErrorMessage() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearErrorMessage() => $_clearField(2);
|
||||
}
|
||||
|
||||
const $core.bool _omitFieldNames =
|
||||
$core.bool.fromEnvironment('protobuf.omit_field_names');
|
||||
const $core.bool _omitMessageNames =
|
||||
|
|
|
|||
|
|
@ -180,3 +180,191 @@ final $typed_data.Uint8List bootstrapCommandResponseDescriptor =
|
|||
$convert.base64Decode(
|
||||
'ChhCb290c3RyYXBDb21tYW5kUmVzcG9uc2USKwoRYm9vdHN0cmFwX2NvbW1hbmQYASABKAlSEG'
|
||||
'Jvb3RzdHJhcENvbW1hbmQ=');
|
||||
|
||||
@$core.Deprecated('Use jobClaimRequestDescriptor instead')
|
||||
const JobClaimRequest$json = {
|
||||
'1': 'JobClaimRequest',
|
||||
'2': [
|
||||
{'1': 'runner_id', '3': 1, '4': 1, '5': 9, '10': 'runnerId'},
|
||||
{'1': 'job_id', '3': 2, '4': 1, '5': 9, '10': 'jobId'},
|
||||
{'1': 'execution_id', '3': 3, '4': 1, '5': 9, '10': 'executionId'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `JobClaimRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List jobClaimRequestDescriptor = $convert.base64Decode(
|
||||
'Cg9Kb2JDbGFpbVJlcXVlc3QSGwoJcnVubmVyX2lkGAEgASgJUghydW5uZXJJZBIVCgZqb2JfaW'
|
||||
'QYAiABKAlSBWpvYklkEiEKDGV4ZWN1dGlvbl9pZBgDIAEoCVILZXhlY3V0aW9uSWQ=');
|
||||
|
||||
@$core.Deprecated('Use jobClaimResponseDescriptor instead')
|
||||
const JobClaimResponse$json = {
|
||||
'1': 'JobClaimResponse',
|
||||
'2': [
|
||||
{'1': 'accepted', '3': 1, '4': 1, '5': 8, '10': 'accepted'},
|
||||
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
|
||||
{'1': 'job_id', '3': 3, '4': 1, '5': 9, '10': 'jobId'},
|
||||
{'1': 'execution_id', '3': 4, '4': 1, '5': 9, '10': 'executionId'},
|
||||
{'1': 'state', '3': 5, '4': 1, '5': 9, '10': 'state'},
|
||||
{'1': 'runner_id', '3': 6, '4': 1, '5': 9, '10': 'runnerId'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `JobClaimResponse`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List jobClaimResponseDescriptor = $convert.base64Decode(
|
||||
'ChBKb2JDbGFpbVJlc3BvbnNlEhoKCGFjY2VwdGVkGAEgASgIUghhY2NlcHRlZBIjCg1lcnJvcl'
|
||||
'9tZXNzYWdlGAIgASgJUgxlcnJvck1lc3NhZ2USFQoGam9iX2lkGAMgASgJUgVqb2JJZBIhCgxl'
|
||||
'eGVjdXRpb25faWQYBCABKAlSC2V4ZWN1dGlvbklkEhQKBXN0YXRlGAUgASgJUgVzdGF0ZRIbCg'
|
||||
'lydW5uZXJfaWQYBiABKAlSCHJ1bm5lcklk');
|
||||
|
||||
@$core.Deprecated('Use stepEventReportDescriptor instead')
|
||||
const StepEventReport$json = {
|
||||
'1': 'StepEventReport',
|
||||
'2': [
|
||||
{'1': 'step_id', '3': 1, '4': 1, '5': 5, '10': 'stepId'},
|
||||
{'1': 'workflow_index', '3': 2, '4': 1, '5': 5, '10': 'workflowIndex'},
|
||||
{'1': 'step_type', '3': 3, '4': 1, '5': 9, '10': 'stepType'},
|
||||
{'1': 'event', '3': 4, '4': 1, '5': 9, '10': 'event'},
|
||||
{'1': 'timestamp', '3': 5, '4': 1, '5': 9, '10': 'timestamp'},
|
||||
{'1': 'command_id', '3': 6, '4': 1, '5': 9, '10': 'commandId'},
|
||||
{'1': 'command_type', '3': 7, '4': 1, '5': 9, '10': 'commandType'},
|
||||
{
|
||||
'1': 'error',
|
||||
'3': 8,
|
||||
'4': 3,
|
||||
'5': 11,
|
||||
'6': '.oto.runner.v1.StepEventReport.ErrorEntry',
|
||||
'10': 'error'
|
||||
},
|
||||
],
|
||||
'3': [StepEventReport_ErrorEntry$json],
|
||||
};
|
||||
|
||||
@$core.Deprecated('Use stepEventReportDescriptor instead')
|
||||
const StepEventReport_ErrorEntry$json = {
|
||||
'1': 'ErrorEntry',
|
||||
'2': [
|
||||
{'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},
|
||||
{'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'},
|
||||
],
|
||||
'7': {'7': true},
|
||||
};
|
||||
|
||||
/// Descriptor for `StepEventReport`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List stepEventReportDescriptor = $convert.base64Decode(
|
||||
'Cg9TdGVwRXZlbnRSZXBvcnQSFwoHc3RlcF9pZBgBIAEoBVIGc3RlcElkEiUKDndvcmtmbG93X2'
|
||||
'luZGV4GAIgASgFUg13b3JrZmxvd0luZGV4EhsKCXN0ZXBfdHlwZRgDIAEoCVIIc3RlcFR5cGUS'
|
||||
'FAoFZXZlbnQYBCABKAlSBWV2ZW50EhwKCXRpbWVzdGFtcBgFIAEoCVIJdGltZXN0YW1wEh0KCm'
|
||||
'NvbW1hbmRfaWQYBiABKAlSCWNvbW1hbmRJZBIhCgxjb21tYW5kX3R5cGUYByABKAlSC2NvbW1h'
|
||||
'bmRUeXBlEj8KBWVycm9yGAggAygLMikub3RvLnJ1bm5lci52MS5TdGVwRXZlbnRSZXBvcnQuRX'
|
||||
'Jyb3JFbnRyeVIFZXJyb3IaOAoKRXJyb3JFbnRyeRIQCgNrZXkYASABKAlSA2tleRIUCgV2YWx1'
|
||||
'ZRgCIAEoCVIFdmFsdWU6AjgB');
|
||||
|
||||
@$core.Deprecated('Use executionReportRequestDescriptor instead')
|
||||
const ExecutionReportRequest$json = {
|
||||
'1': 'ExecutionReportRequest',
|
||||
'2': [
|
||||
{'1': 'runner_id', '3': 1, '4': 1, '5': 9, '10': 'runnerId'},
|
||||
{'1': 'job_id', '3': 2, '4': 1, '5': 9, '10': 'jobId'},
|
||||
{'1': 'execution_id', '3': 3, '4': 1, '5': 9, '10': 'executionId'},
|
||||
{'1': 'success', '3': 4, '4': 1, '5': 8, '10': 'success'},
|
||||
{'1': 'exit_code', '3': 5, '4': 1, '5': 5, '10': 'exitCode'},
|
||||
{'1': 'message', '3': 6, '4': 1, '5': 9, '10': 'message'},
|
||||
{
|
||||
'1': 'step_events',
|
||||
'3': 7,
|
||||
'4': 3,
|
||||
'5': 11,
|
||||
'6': '.oto.runner.v1.StepEventReport',
|
||||
'10': 'stepEvents'
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `ExecutionReportRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List executionReportRequestDescriptor = $convert.base64Decode(
|
||||
'ChZFeGVjdXRpb25SZXBvcnRSZXF1ZXN0EhsKCXJ1bm5lcl9pZBgBIAEoCVIIcnVubmVySWQSFQ'
|
||||
'oGam9iX2lkGAIgASgJUgVqb2JJZBIhCgxleGVjdXRpb25faWQYAyABKAlSC2V4ZWN1dGlvbklk'
|
||||
'EhgKB3N1Y2Nlc3MYBCABKAhSB3N1Y2Nlc3MSGwoJZXhpdF9jb2RlGAUgASgFUghleGl0Q29kZR'
|
||||
'IYCgdtZXNzYWdlGAYgASgJUgdtZXNzYWdlEj8KC3N0ZXBfZXZlbnRzGAcgAygLMh4ub3RvLnJ1'
|
||||
'bm5lci52MS5TdGVwRXZlbnRSZXBvcnRSCnN0ZXBFdmVudHM=');
|
||||
|
||||
@$core.Deprecated('Use executionReportResponseDescriptor instead')
|
||||
const ExecutionReportResponse$json = {
|
||||
'1': 'ExecutionReportResponse',
|
||||
'2': [
|
||||
{'1': 'accepted', '3': 1, '4': 1, '5': 8, '10': 'accepted'},
|
||||
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
|
||||
{'1': 'job_id', '3': 3, '4': 1, '5': 9, '10': 'jobId'},
|
||||
{'1': 'execution_id', '3': 4, '4': 1, '5': 9, '10': 'executionId'},
|
||||
{'1': 'state', '3': 5, '4': 1, '5': 9, '10': 'state'},
|
||||
{'1': 'runner_id', '3': 6, '4': 1, '5': 9, '10': 'runnerId'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `ExecutionReportResponse`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List executionReportResponseDescriptor = $convert.base64Decode(
|
||||
'ChdFeGVjdXRpb25SZXBvcnRSZXNwb25zZRIaCghhY2NlcHRlZBgBIAEoCFIIYWNjZXB0ZWQSIw'
|
||||
'oNZXJyb3JfbWVzc2FnZRgCIAEoCVIMZXJyb3JNZXNzYWdlEhUKBmpvYl9pZBgDIAEoCVIFam9i'
|
||||
'SWQSIQoMZXhlY3V0aW9uX2lkGAQgASgJUgtleGVjdXRpb25JZBIUCgVzdGF0ZRgFIAEoCVIFc3'
|
||||
'RhdGUSGwoJcnVubmVyX2lkGAYgASgJUghydW5uZXJJZA==');
|
||||
|
||||
@$core.Deprecated('Use logAppendRequestDescriptor instead')
|
||||
const LogAppendRequest$json = {
|
||||
'1': 'LogAppendRequest',
|
||||
'2': [
|
||||
{'1': 'runner_id', '3': 1, '4': 1, '5': 9, '10': 'runnerId'},
|
||||
{'1': 'execution_id', '3': 2, '4': 1, '5': 9, '10': 'executionId'},
|
||||
{'1': 'line', '3': 3, '4': 1, '5': 9, '10': 'line'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `LogAppendRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List logAppendRequestDescriptor = $convert.base64Decode(
|
||||
'ChBMb2dBcHBlbmRSZXF1ZXN0EhsKCXJ1bm5lcl9pZBgBIAEoCVIIcnVubmVySWQSIQoMZXhlY3'
|
||||
'V0aW9uX2lkGAIgASgJUgtleGVjdXRpb25JZBISCgRsaW5lGAMgASgJUgRsaW5l');
|
||||
|
||||
@$core.Deprecated('Use logAppendResponseDescriptor instead')
|
||||
const LogAppendResponse$json = {
|
||||
'1': 'LogAppendResponse',
|
||||
'2': [
|
||||
{'1': 'accepted', '3': 1, '4': 1, '5': 8, '10': 'accepted'},
|
||||
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `LogAppendResponse`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List logAppendResponseDescriptor = $convert.base64Decode(
|
||||
'ChFMb2dBcHBlbmRSZXNwb25zZRIaCghhY2NlcHRlZBgBIAEoCFIIYWNjZXB0ZWQSIwoNZXJyb3'
|
||||
'JfbWVzc2FnZRgCIAEoCVIMZXJyb3JNZXNzYWdl');
|
||||
|
||||
@$core.Deprecated('Use artifactReportRequestDescriptor instead')
|
||||
const ArtifactReportRequest$json = {
|
||||
'1': 'ArtifactReportRequest',
|
||||
'2': [
|
||||
{'1': 'runner_id', '3': 1, '4': 1, '5': 9, '10': 'runnerId'},
|
||||
{'1': 'execution_id', '3': 2, '4': 1, '5': 9, '10': 'executionId'},
|
||||
{'1': 'name', '3': 3, '4': 1, '5': 9, '10': 'name'},
|
||||
{'1': 'path', '3': 4, '4': 1, '5': 9, '10': 'path'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `ArtifactReportRequest`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List artifactReportRequestDescriptor = $convert.base64Decode(
|
||||
'ChVBcnRpZmFjdFJlcG9ydFJlcXVlc3QSGwoJcnVubmVyX2lkGAEgASgJUghydW5uZXJJZBIhCg'
|
||||
'xleGVjdXRpb25faWQYAiABKAlSC2V4ZWN1dGlvbklkEhIKBG5hbWUYAyABKAlSBG5hbWUSEgoE'
|
||||
'cGF0aBgEIAEoCVIEcGF0aA==');
|
||||
|
||||
@$core.Deprecated('Use artifactReportResponseDescriptor instead')
|
||||
const ArtifactReportResponse$json = {
|
||||
'1': 'ArtifactReportResponse',
|
||||
'2': [
|
||||
{'1': 'accepted', '3': 1, '4': 1, '5': 8, '10': 'accepted'},
|
||||
{'1': 'error_message', '3': 2, '4': 1, '5': 9, '10': 'errorMessage'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `ArtifactReportResponse`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List artifactReportResponseDescriptor =
|
||||
$convert.base64Decode(
|
||||
'ChZBcnRpZmFjdFJlcG9ydFJlc3BvbnNlEhoKCGFjY2VwdGVkGAEgASgIUghhY2NlcHRlZBIjCg'
|
||||
'1lcnJvcl9tZXNzYWdlGAIgASgJUgxlcnJvck1lc3NhZ2U=');
|
||||
|
|
|
|||
272
apps/runner/lib/oto/agent/oto_server_job_client.dart
Normal file
272
apps/runner/lib/oto/agent/oto_server_job_client.dart
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:oto/oto/agent/oto/runner.pb.dart' as oto;
|
||||
import 'package:oto/oto/core/build_result.dart';
|
||||
import 'package:oto/oto/core/execution_context.dart';
|
||||
|
||||
class JobClaimResult {
|
||||
final bool accepted;
|
||||
final String? errorMessage;
|
||||
final String jobId;
|
||||
final String executionId;
|
||||
final String state;
|
||||
|
||||
const JobClaimResult({
|
||||
required this.accepted,
|
||||
required this.jobId,
|
||||
required this.executionId,
|
||||
required this.state,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
factory JobClaimResult.fromJson(Map<String, dynamic> json) {
|
||||
return JobClaimResult(
|
||||
accepted: json['accepted'] == true,
|
||||
errorMessage: _emptyToNull(
|
||||
(json['error_message'] ?? json['errorMessage'] ?? '').toString(),
|
||||
),
|
||||
jobId: (json['job_id'] ?? json['jobId'] ?? '').toString(),
|
||||
executionId: (json['execution_id'] ?? json['executionId'] ?? '')
|
||||
.toString(),
|
||||
state: (json['state'] ?? '').toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ExecutionReportResult {
|
||||
final bool accepted;
|
||||
final String? errorMessage;
|
||||
final String jobId;
|
||||
final String executionId;
|
||||
final String state;
|
||||
|
||||
const ExecutionReportResult({
|
||||
required this.accepted,
|
||||
required this.jobId,
|
||||
required this.executionId,
|
||||
required this.state,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
factory ExecutionReportResult.fromJson(Map<String, dynamic> json) {
|
||||
return ExecutionReportResult(
|
||||
accepted: json['accepted'] == true,
|
||||
errorMessage: _emptyToNull(
|
||||
(json['error_message'] ?? json['errorMessage'] ?? '').toString(),
|
||||
),
|
||||
jobId: (json['job_id'] ?? json['jobId'] ?? '').toString(),
|
||||
executionId: (json['execution_id'] ?? json['executionId'] ?? '')
|
||||
.toString(),
|
||||
state: (json['state'] ?? '').toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class OtoServerJobClient {
|
||||
final String serverUrl;
|
||||
final String runnerId;
|
||||
final http.Client _client;
|
||||
final bool _shouldCloseClient;
|
||||
|
||||
OtoServerJobClient({
|
||||
required this.serverUrl,
|
||||
required this.runnerId,
|
||||
http.Client? client,
|
||||
}) : _client = client ?? http.Client(),
|
||||
_shouldCloseClient = client == null;
|
||||
|
||||
Future<JobClaimResult> claimJob({
|
||||
required String jobId,
|
||||
required String executionId,
|
||||
}) async {
|
||||
final request = oto.JobClaimRequest()
|
||||
..runnerId = runnerId
|
||||
..jobId = jobId
|
||||
..executionId = executionId;
|
||||
final response = await _postJson(
|
||||
_runnerUri('/jobs/claim'),
|
||||
_jobClaimRequestJson(request),
|
||||
);
|
||||
return JobClaimResult.fromJson(response);
|
||||
}
|
||||
|
||||
Future<ExecutionReportResult> reportExecution({
|
||||
required String jobId,
|
||||
required String executionId,
|
||||
required BuildResult result,
|
||||
}) async {
|
||||
final request = oto.ExecutionReportRequest()
|
||||
..runnerId = runnerId
|
||||
..jobId = jobId
|
||||
..executionId = executionId
|
||||
..success = result.success
|
||||
..exitCode = result.exitCode
|
||||
..message = result.message
|
||||
..stepEvents.addAll(result.stepEvents.map(_stepEventReport));
|
||||
final response = await _postJson(
|
||||
_runnerUri('/executions/${Uri.encodeComponent(executionId)}/report'),
|
||||
_executionReportRequestJson(request, result),
|
||||
);
|
||||
return ExecutionReportResult.fromJson(response);
|
||||
}
|
||||
|
||||
Future<void> appendLog({
|
||||
required String executionId,
|
||||
required String line,
|
||||
}) async {
|
||||
final request = oto.LogAppendRequest()
|
||||
..runnerId = runnerId
|
||||
..executionId = executionId
|
||||
..line = line;
|
||||
final response = await _postJson(
|
||||
_runnerUri('/executions/${Uri.encodeComponent(executionId)}/logs'),
|
||||
_logAppendRequestJson(request),
|
||||
expectedStatus: HttpStatus.created,
|
||||
);
|
||||
if (response['accepted'] != true) {
|
||||
throw HttpException(
|
||||
(response['error_message'] ??
|
||||
response['errorMessage'] ??
|
||||
'log rejected')
|
||||
.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> reportArtifact({
|
||||
required String executionId,
|
||||
required String name,
|
||||
required String path,
|
||||
}) async {
|
||||
final request = oto.ArtifactReportRequest()
|
||||
..runnerId = runnerId
|
||||
..executionId = executionId
|
||||
..name = name
|
||||
..path = path;
|
||||
final response = await _postJson(
|
||||
_runnerUri('/executions/${Uri.encodeComponent(executionId)}/artifacts'),
|
||||
_artifactReportRequestJson(request),
|
||||
expectedStatus: HttpStatus.created,
|
||||
);
|
||||
if (response['accepted'] != true) {
|
||||
throw HttpException(
|
||||
(response['error_message'] ??
|
||||
response['errorMessage'] ??
|
||||
'artifact rejected')
|
||||
.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void close() {
|
||||
if (_shouldCloseClient) {
|
||||
_client.close();
|
||||
}
|
||||
}
|
||||
|
||||
Uri _runnerUri(String suffix) {
|
||||
final runnerPath =
|
||||
'/api/v1/runners/${Uri.encodeComponent(runnerId)}$suffix';
|
||||
return _apiUri(serverUrl, runnerPath);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> _postJson(
|
||||
Uri uri,
|
||||
Map<String, dynamic> body, {
|
||||
int expectedStatus = HttpStatus.ok,
|
||||
}) async {
|
||||
final response = await _client
|
||||
.post(
|
||||
uri,
|
||||
headers: {'content-type': 'application/json'},
|
||||
body: jsonEncode(body),
|
||||
)
|
||||
.timeout(const Duration(seconds: 5));
|
||||
if (response.statusCode != expectedStatus) {
|
||||
throw HttpException(
|
||||
'OTO Server request failed with HTTP ${response.statusCode}',
|
||||
);
|
||||
}
|
||||
final decoded = jsonDecode(response.body);
|
||||
if (decoded is! Map<String, dynamic>) {
|
||||
throw const FormatException('Invalid OTO Server response body');
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
}
|
||||
|
||||
Uri _apiUri(String serverUrl, String endpointPath) {
|
||||
var raw = serverUrl;
|
||||
if (!raw.contains('://')) {
|
||||
raw = 'http://$raw';
|
||||
}
|
||||
final uri = Uri.parse(raw);
|
||||
if (uri.host.isEmpty) {
|
||||
throw FormatException('Invalid server url: "$serverUrl"');
|
||||
}
|
||||
return uri.replace(path: _joinPath(uri.path, endpointPath));
|
||||
}
|
||||
|
||||
String _joinPath(String basePath, String endpointPath) {
|
||||
final base = basePath.endsWith('/')
|
||||
? basePath.substring(0, basePath.length - 1)
|
||||
: basePath;
|
||||
return '$base$endpointPath';
|
||||
}
|
||||
|
||||
Map<String, dynamic> _jobClaimRequestJson(oto.JobClaimRequest request) => {
|
||||
'runner_id': request.runnerId,
|
||||
'job_id': request.jobId,
|
||||
'execution_id': request.executionId,
|
||||
};
|
||||
|
||||
Map<String, dynamic> _executionReportRequestJson(
|
||||
oto.ExecutionReportRequest request,
|
||||
BuildResult result,
|
||||
) {
|
||||
final resultJson = result.toJson();
|
||||
return {
|
||||
'runner_id': request.runnerId,
|
||||
'job_id': request.jobId,
|
||||
'execution_id': request.executionId,
|
||||
'success': request.success,
|
||||
'exit_code': request.exitCode,
|
||||
'message': request.message,
|
||||
'step_events': resultJson['stepEvents'],
|
||||
'execution_result': resultJson,
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> _logAppendRequestJson(oto.LogAppendRequest request) => {
|
||||
'runner_id': request.runnerId,
|
||||
'execution_id': request.executionId,
|
||||
'line': request.line,
|
||||
};
|
||||
|
||||
Map<String, dynamic> _artifactReportRequestJson(
|
||||
oto.ArtifactReportRequest request,
|
||||
) => {
|
||||
'runner_id': request.runnerId,
|
||||
'execution_id': request.executionId,
|
||||
'name': request.name,
|
||||
'path': request.path,
|
||||
};
|
||||
|
||||
oto.StepEventReport _stepEventReport(StepEvent event) {
|
||||
final report = oto.StepEventReport()
|
||||
..stepId = event.stepId
|
||||
..workflowIndex = event.workflowIndex
|
||||
..stepType = event.stepType
|
||||
..event = event.event
|
||||
..timestamp = event.timestamp
|
||||
..commandId = event.commandId ?? ''
|
||||
..commandType = event.commandType ?? '';
|
||||
if (event.error != null) {
|
||||
report.error.addAll(event.error!);
|
||||
}
|
||||
return report;
|
||||
}
|
||||
|
||||
String? _emptyToNull(String value) => value.isEmpty ? null : value;
|
||||
|
|
@ -6,6 +6,9 @@ import 'package:test/test.dart';
|
|||
import 'package:oto/oto/agent/agent_config.dart';
|
||||
import 'package:oto/oto/agent/agent_runner.dart';
|
||||
import 'package:oto/oto/agent/edge_registration_client.dart';
|
||||
import 'package:oto/oto/agent/oto_server_job_client.dart';
|
||||
import 'package:oto/oto/core/build_result.dart';
|
||||
import 'package:oto/oto/core/execution_context.dart';
|
||||
|
||||
class FakeEdgeAgentSession implements EdgeAgentSession {
|
||||
@override
|
||||
|
|
@ -171,29 +174,30 @@ runtime:
|
|||
final disconnectReceived = Completer<void>();
|
||||
|
||||
final serverSub = server.listen((request) async {
|
||||
if (request.method == 'POST' && request.uri.path == '/api/v1/runners/register') {
|
||||
if (request.method == 'POST' &&
|
||||
request.uri.path == '/api/v1/runners/register') {
|
||||
registerReceived.complete();
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(jsonEncode({
|
||||
'accepted': true,
|
||||
'runner_id': 'agent-123',
|
||||
'alias': 'my-agent',
|
||||
}));
|
||||
} else if (request.method == 'POST' && request.uri.path == '/api/v1/runners/agent-123/heartbeat') {
|
||||
..write(
|
||||
jsonEncode({
|
||||
'accepted': true,
|
||||
'runner_id': 'agent-123',
|
||||
'alias': 'my-agent',
|
||||
}),
|
||||
);
|
||||
} else if (request.method == 'POST' &&
|
||||
request.uri.path == '/api/v1/runners/agent-123/heartbeat') {
|
||||
heartbeatReceived.complete();
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(jsonEncode({
|
||||
'success': true,
|
||||
}));
|
||||
} else if (request.method == 'POST' && request.uri.path == '/api/v1/runners/agent-123/disconnect') {
|
||||
..write(jsonEncode({'success': true}));
|
||||
} else if (request.method == 'POST' &&
|
||||
request.uri.path == '/api/v1/runners/agent-123/disconnect') {
|
||||
disconnectReceived.complete();
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(jsonEncode({
|
||||
'success': true,
|
||||
}));
|
||||
..write(jsonEncode({'success': true}));
|
||||
}
|
||||
await request.response.close();
|
||||
});
|
||||
|
|
@ -213,6 +217,8 @@ runtime:
|
|||
|
||||
final session = await client.openSession(config);
|
||||
|
||||
expect(session, isA<OtoServerJobSession>());
|
||||
|
||||
// First heartbeat should be sent automatically
|
||||
await heartbeatReceived.future.timeout(const Duration(seconds: 2));
|
||||
|
||||
|
|
@ -227,75 +233,79 @@ runtime:
|
|||
}
|
||||
});
|
||||
|
||||
test('does not send heartbeat or disconnect on rejected registration', () async {
|
||||
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
||||
var heartbeatReceived = false;
|
||||
var disconnectReceived = false;
|
||||
test(
|
||||
'does not send heartbeat or disconnect on rejected registration',
|
||||
() async {
|
||||
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
||||
var heartbeatReceived = false;
|
||||
var disconnectReceived = false;
|
||||
|
||||
final serverSub = server.listen((request) async {
|
||||
if (request.method == 'POST' && request.uri.path == '/api/v1/runners/register') {
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(jsonEncode({
|
||||
'accepted': false,
|
||||
'reject_reason': 'Invalid token',
|
||||
}));
|
||||
} else if (request.uri.path.contains('heartbeat')) {
|
||||
heartbeatReceived = true;
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(jsonEncode({'success': true}));
|
||||
} else if (request.uri.path.contains('disconnect')) {
|
||||
disconnectReceived = true;
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(jsonEncode({'success': true}));
|
||||
final serverSub = server.listen((request) async {
|
||||
if (request.method == 'POST' &&
|
||||
request.uri.path == '/api/v1/runners/register') {
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(
|
||||
jsonEncode({
|
||||
'accepted': false,
|
||||
'reject_reason': 'Invalid token',
|
||||
}),
|
||||
);
|
||||
} else if (request.uri.path.contains('heartbeat')) {
|
||||
heartbeatReceived = true;
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(jsonEncode({'success': true}));
|
||||
} else if (request.uri.path.contains('disconnect')) {
|
||||
disconnectReceived = true;
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(jsonEncode({'success': true}));
|
||||
}
|
||||
await request.response.close();
|
||||
});
|
||||
|
||||
try {
|
||||
final config = AgentConfig(
|
||||
agent: validConfig.agent,
|
||||
server: ServerConnectionConfig(
|
||||
url: 'http://${server.address.host}:${server.port}',
|
||||
),
|
||||
runtime: validConfig.runtime,
|
||||
);
|
||||
final client = OtoServerRegistrationClient(
|
||||
commandTypes: ['Shell', 'Git'],
|
||||
heartbeatInterval: const Duration(milliseconds: 50),
|
||||
);
|
||||
|
||||
final session = await client.openSession(config);
|
||||
expect(session.result.accepted, isFalse);
|
||||
|
||||
// Wait a short duration to ensure no heartbeat is sent
|
||||
await Future<void>.delayed(const Duration(milliseconds: 200));
|
||||
expect(heartbeatReceived, isFalse);
|
||||
|
||||
await session.close();
|
||||
// Wait a short duration to ensure no disconnect is sent
|
||||
await Future<void>.delayed(const Duration(milliseconds: 100));
|
||||
expect(disconnectReceived, isFalse);
|
||||
} finally {
|
||||
await serverSub.cancel();
|
||||
await server.close(force: true);
|
||||
}
|
||||
await request.response.close();
|
||||
});
|
||||
|
||||
try {
|
||||
final config = AgentConfig(
|
||||
agent: validConfig.agent,
|
||||
server: ServerConnectionConfig(
|
||||
url: 'http://${server.address.host}:${server.port}',
|
||||
),
|
||||
runtime: validConfig.runtime,
|
||||
);
|
||||
final client = OtoServerRegistrationClient(
|
||||
commandTypes: ['Shell', 'Git'],
|
||||
heartbeatInterval: const Duration(milliseconds: 50),
|
||||
);
|
||||
|
||||
final session = await client.openSession(config);
|
||||
expect(session.result.accepted, isFalse);
|
||||
|
||||
// Wait a short duration to ensure no heartbeat is sent
|
||||
await Future<void>.delayed(const Duration(milliseconds: 200));
|
||||
expect(heartbeatReceived, isFalse);
|
||||
|
||||
await session.close();
|
||||
// Wait a short duration to ensure no disconnect is sent
|
||||
await Future<void>.delayed(const Duration(milliseconds: 100));
|
||||
expect(disconnectReceived, isFalse);
|
||||
} finally {
|
||||
await serverSub.cancel();
|
||||
await server.close(force: true);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test('session close cancels future heartbeats', () async {
|
||||
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
||||
var heartbeatCount = 0;
|
||||
|
||||
final serverSub = server.listen((request) async {
|
||||
if (request.method == 'POST' && request.uri.path == '/api/v1/runners/register') {
|
||||
if (request.method == 'POST' &&
|
||||
request.uri.path == '/api/v1/runners/register') {
|
||||
request.response
|
||||
..headers.contentType = ContentType.json
|
||||
..write(jsonEncode({
|
||||
'accepted': true,
|
||||
'runner_id': 'agent-123',
|
||||
}));
|
||||
..write(jsonEncode({'accepted': true, 'runner_id': 'agent-123'}));
|
||||
} else if (request.uri.path.contains('heartbeat')) {
|
||||
heartbeatCount++;
|
||||
request.response
|
||||
|
|
@ -339,6 +349,134 @@ runtime:
|
|||
await server.close(force: true);
|
||||
}
|
||||
});
|
||||
|
||||
test('job client claims jobs and reports build results', () async {
|
||||
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
||||
final claimReceived = Completer<Map<String, dynamic>>();
|
||||
final reportReceived = Completer<Map<String, dynamic>>();
|
||||
final logReceived = Completer<Map<String, dynamic>>();
|
||||
final artifactReceived = Completer<Map<String, dynamic>>();
|
||||
|
||||
final serverSub = server.listen((request) async {
|
||||
final bodyText = await utf8.decoder.bind(request).join();
|
||||
final body = bodyText.isEmpty
|
||||
? <String, dynamic>{}
|
||||
: jsonDecode(bodyText) as Map<String, dynamic>;
|
||||
request.response.headers.contentType = ContentType.json;
|
||||
if (request.method == 'POST' &&
|
||||
request.uri.path == '/api/v1/runners/agent-123/jobs/claim') {
|
||||
claimReceived.complete(body);
|
||||
request.response.write(
|
||||
jsonEncode({
|
||||
'accepted': true,
|
||||
'runner_id': 'agent-123',
|
||||
'job_id': 'job-123',
|
||||
'execution_id': 'exec-123',
|
||||
'state': 'running',
|
||||
}),
|
||||
);
|
||||
} else if (request.method == 'POST' &&
|
||||
request.uri.path ==
|
||||
'/api/v1/runners/agent-123/executions/exec-123/report') {
|
||||
reportReceived.complete(body);
|
||||
request.response.write(
|
||||
jsonEncode({
|
||||
'accepted': true,
|
||||
'runner_id': 'agent-123',
|
||||
'job_id': 'job-123',
|
||||
'execution_id': 'exec-123',
|
||||
'state': 'succeeded',
|
||||
}),
|
||||
);
|
||||
} else if (request.method == 'POST' &&
|
||||
request.uri.path ==
|
||||
'/api/v1/runners/agent-123/executions/exec-123/logs') {
|
||||
logReceived.complete(body);
|
||||
request.response.statusCode = HttpStatus.created;
|
||||
request.response.write(jsonEncode({'accepted': true}));
|
||||
} else if (request.method == 'POST' &&
|
||||
request.uri.path ==
|
||||
'/api/v1/runners/agent-123/executions/exec-123/artifacts') {
|
||||
artifactReceived.complete(body);
|
||||
request.response.statusCode = HttpStatus.created;
|
||||
request.response.write(jsonEncode({'accepted': true}));
|
||||
} else {
|
||||
request.response.statusCode = HttpStatus.notFound;
|
||||
request.response.write(jsonEncode({'error': 'not found'}));
|
||||
}
|
||||
await request.response.close();
|
||||
});
|
||||
|
||||
final client = OtoServerJobClient(
|
||||
serverUrl: 'http://${server.address.host}:${server.port}',
|
||||
runnerId: 'agent-123',
|
||||
);
|
||||
|
||||
try {
|
||||
final claim = await client.claimJob(
|
||||
jobId: 'job-123',
|
||||
executionId: 'exec-123',
|
||||
);
|
||||
expect(claim.accepted, isTrue);
|
||||
expect(claim.state, 'running');
|
||||
|
||||
final result = BuildResult.success(
|
||||
stepEvents: [
|
||||
StepEvent(
|
||||
stepId: 0,
|
||||
workflowIndex: 0,
|
||||
stepType: 'command',
|
||||
event: 'completed',
|
||||
timestamp: '2026-06-05T12:00:00Z',
|
||||
commandId: 'build',
|
||||
commandType: 'Shell',
|
||||
),
|
||||
],
|
||||
);
|
||||
final report = await client.reportExecution(
|
||||
jobId: 'job-123',
|
||||
executionId: 'exec-123',
|
||||
result: result,
|
||||
);
|
||||
expect(report.accepted, isTrue);
|
||||
expect(report.state, 'succeeded');
|
||||
|
||||
await client.appendLog(
|
||||
executionId: 'exec-123',
|
||||
line: 'build completed',
|
||||
);
|
||||
await client.reportArtifact(
|
||||
executionId: 'exec-123',
|
||||
name: 'binary',
|
||||
path: '/dist/app',
|
||||
);
|
||||
|
||||
final claimPayload = await claimReceived.future;
|
||||
expect(claimPayload['runner_id'], 'agent-123');
|
||||
expect(claimPayload['job_id'], 'job-123');
|
||||
expect(claimPayload['execution_id'], 'exec-123');
|
||||
|
||||
final reportPayload = await reportReceived.future;
|
||||
expect(reportPayload['success'], isTrue);
|
||||
expect(reportPayload['exit_code'], 0);
|
||||
expect(reportPayload['message'], 'Build completed successfully.');
|
||||
expect(reportPayload['execution_result'], isA<Map<String, dynamic>>());
|
||||
final stepEvents = reportPayload['step_events'] as List<dynamic>;
|
||||
expect(stepEvents, hasLength(1));
|
||||
expect(stepEvents.first, containsPair('commandId', 'build'));
|
||||
|
||||
final logPayload = await logReceived.future;
|
||||
expect(logPayload['line'], 'build completed');
|
||||
|
||||
final artifactPayload = await artifactReceived.future;
|
||||
expect(artifactPayload['name'], 'binary');
|
||||
expect(artifactPayload['path'], '/dist/app');
|
||||
} finally {
|
||||
client.close();
|
||||
await serverSub.cancel();
|
||||
await server.close(force: true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
group('AgentRunner', () {
|
||||
|
|
@ -387,6 +525,30 @@ runtime:
|
|||
expect(fakeClient.lastSession!.closed, isTrue);
|
||||
});
|
||||
|
||||
test('AgentRunner runs injected job loop after registration', () async {
|
||||
final fakeClient = FakeEdgeRegistrationClient((config) {
|
||||
return RegistrationResult.accepted('node-123', 'alias-123', {
|
||||
'concurrency': 1,
|
||||
});
|
||||
});
|
||||
var jobLoopRan = false;
|
||||
|
||||
final runner = DefaultAgentRunner(
|
||||
client: fakeClient,
|
||||
onLog: (msg) {},
|
||||
runJobs: (config, session) async {
|
||||
jobLoopRan = true;
|
||||
expect(config.agent.id, 'agent-123');
|
||||
expect(session.result.accepted, isTrue);
|
||||
},
|
||||
waitForShutdown: () async {},
|
||||
);
|
||||
|
||||
await runner.run(validConfig);
|
||||
|
||||
expect(jobLoopRan, isTrue);
|
||||
});
|
||||
|
||||
test(
|
||||
'AgentRunner reports rejected registration and closes session',
|
||||
() async {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import 'package:http/http.dart' as http;
|
|||
import 'package:test/test.dart';
|
||||
import 'package:oto/oto/agent/agent_config.dart';
|
||||
import 'package:oto/oto/agent/edge_registration_client.dart';
|
||||
import 'package:oto/oto/core/build_result.dart';
|
||||
import 'package:oto/oto/core/execution_context.dart';
|
||||
|
||||
const _host = '127.0.0.1';
|
||||
const _token = 'oto-smoke-token';
|
||||
|
|
@ -342,6 +344,176 @@ fi
|
|||
},
|
||||
timeout: const Timeout(Duration(seconds: 30)),
|
||||
);
|
||||
|
||||
test(
|
||||
'OTO Server owns job execution logs and artifacts reported by runner',
|
||||
() async {
|
||||
final port = await _freePort();
|
||||
final serverAddr = '$_host:$port';
|
||||
const jobId = 'oto-smoke-job';
|
||||
const executionId = 'oto-smoke-execution';
|
||||
|
||||
final serverProcess = await Process.start(
|
||||
'go',
|
||||
['run', './cmd/oto-core'],
|
||||
workingDirectory: '../../services/core',
|
||||
environment: {'OTO_CORE_ADDR': serverAddr},
|
||||
);
|
||||
|
||||
final output = StringBuffer();
|
||||
final stdoutSub = serverProcess.stdout
|
||||
.transform(systemEncoding.decoder)
|
||||
.listen(output.write, onError: output.write);
|
||||
final stderrSub = serverProcess.stderr
|
||||
.transform(systemEncoding.decoder)
|
||||
.listen(output.write, onError: output.write);
|
||||
|
||||
try {
|
||||
await _waitForPort(_host, port, serverProcess, output);
|
||||
|
||||
final agentConfig = AgentConfig(
|
||||
agent: const AgentIdentityConfig(
|
||||
id: _runnerId,
|
||||
alias: _runnerAlias,
|
||||
enrollmentToken: _token,
|
||||
),
|
||||
server: ServerConnectionConfig(url: 'http://$serverAddr'),
|
||||
runtime: const AgentRuntimeConfig(
|
||||
installDir: '/tmp/install',
|
||||
workspaceRoot: '/tmp/workspace',
|
||||
logDir: '/tmp/log',
|
||||
),
|
||||
);
|
||||
|
||||
final registrationClient = OtoServerRegistrationClient(
|
||||
commandTypes: ['Shell', 'Git'],
|
||||
heartbeatInterval: const Duration(milliseconds: 200),
|
||||
);
|
||||
final session = await registrationClient.openSession(agentConfig);
|
||||
try {
|
||||
expect(session.result.accepted, isTrue);
|
||||
expect(session, isA<OtoServerJobSession>());
|
||||
final jobs = (session as OtoServerJobSession).jobs;
|
||||
|
||||
final httpClient = http.Client();
|
||||
try {
|
||||
final createJobResponse = await httpClient.post(
|
||||
Uri.parse('http://$serverAddr/api/v1/jobs'),
|
||||
headers: {'content-type': 'application/json'},
|
||||
body: jsonEncode({'id': jobId, 'name': 'smoke build'}),
|
||||
);
|
||||
expect(
|
||||
createJobResponse.statusCode,
|
||||
equals(201),
|
||||
reason: 'Create job failed: ${createJobResponse.body}',
|
||||
);
|
||||
|
||||
final claim = await jobs.claimJob(
|
||||
jobId: jobId,
|
||||
executionId: executionId,
|
||||
);
|
||||
expect(claim.accepted, isTrue);
|
||||
expect(claim.state, 'running');
|
||||
|
||||
await jobs.appendLog(
|
||||
executionId: executionId,
|
||||
line: 'runner started smoke build',
|
||||
);
|
||||
await jobs.reportArtifact(
|
||||
executionId: executionId,
|
||||
name: 'smoke-report',
|
||||
path: '/tmp/oto-smoke/report.txt',
|
||||
);
|
||||
final report = await jobs.reportExecution(
|
||||
jobId: jobId,
|
||||
executionId: executionId,
|
||||
result: BuildResult.success(
|
||||
stepEvents: [
|
||||
StepEvent(
|
||||
stepId: 0,
|
||||
workflowIndex: 0,
|
||||
stepType: 'command',
|
||||
event: 'started',
|
||||
timestamp: DateTime.now().toUtc().toIso8601String(),
|
||||
commandId: 'smoke-build',
|
||||
commandType: 'Shell',
|
||||
),
|
||||
StepEvent(
|
||||
stepId: 0,
|
||||
workflowIndex: 0,
|
||||
stepType: 'command',
|
||||
event: 'completed',
|
||||
timestamp: DateTime.now().toUtc().toIso8601String(),
|
||||
commandId: 'smoke-build',
|
||||
commandType: 'Shell',
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
expect(report.accepted, isTrue);
|
||||
expect(report.state, 'succeeded');
|
||||
|
||||
final job = await _getJson(
|
||||
httpClient,
|
||||
'http://$serverAddr/api/v1/jobs/$jobId',
|
||||
);
|
||||
expect(job['state'], 'succeeded');
|
||||
expect(job['execution_id'], executionId);
|
||||
|
||||
final execution = await _getJson(
|
||||
httpClient,
|
||||
'http://$serverAddr/api/v1/executions/$executionId',
|
||||
);
|
||||
expect(execution['state'], 'succeeded');
|
||||
expect(execution['job_id'], jobId);
|
||||
|
||||
final logs = await _getJson(
|
||||
httpClient,
|
||||
'http://$serverAddr/api/v1/executions/$executionId/logs',
|
||||
);
|
||||
final logLines = (logs['logs'] as List<dynamic>)
|
||||
.map(
|
||||
(entry) =>
|
||||
(entry as Map<String, dynamic>)['Line'] ?? entry['line'],
|
||||
)
|
||||
.map((line) => line.toString())
|
||||
.toList();
|
||||
expect(logLines, contains('runner started smoke build'));
|
||||
expect(logLines, contains('Build completed successfully.'));
|
||||
|
||||
final artifacts = await _getJson(
|
||||
httpClient,
|
||||
'http://$serverAddr/api/v1/executions/$executionId/artifacts',
|
||||
);
|
||||
final artifactRows = artifacts['artifacts'] as List<dynamic>;
|
||||
expect(artifactRows, hasLength(1));
|
||||
final artifact = artifactRows.single as Map<String, dynamic>;
|
||||
expect(artifact['Name'] ?? artifact['name'], 'smoke-report');
|
||||
expect(
|
||||
artifact['Path'] ?? artifact['path'],
|
||||
'/tmp/oto-smoke/report.txt',
|
||||
);
|
||||
} finally {
|
||||
httpClient.close();
|
||||
}
|
||||
} finally {
|
||||
await session.close();
|
||||
}
|
||||
} finally {
|
||||
serverProcess.kill(ProcessSignal.sigterm);
|
||||
await serverProcess.exitCode.timeout(
|
||||
const Duration(seconds: 5),
|
||||
onTimeout: () {
|
||||
serverProcess.kill(ProcessSignal.sigkill);
|
||||
return serverProcess.exitCode;
|
||||
},
|
||||
);
|
||||
await stdoutSub.cancel();
|
||||
await stderrSub.cancel();
|
||||
}
|
||||
},
|
||||
timeout: const Timeout(Duration(seconds: 30)),
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> _freePort() async {
|
||||
|
|
@ -383,3 +555,9 @@ Future<int?> _tryExitCode(Process process) {
|
|||
.timeout(Duration.zero, onTimeout: () => -1)
|
||||
.then((code) => code == -1 ? null : code);
|
||||
}
|
||||
|
||||
Future<Map<String, dynamic>> _getJson(http.Client client, String url) async {
|
||||
final response = await client.get(Uri.parse(url));
|
||||
expect(response.statusCode, equals(200), reason: response.body);
|
||||
return jsonDecode(response.body) as Map<String, dynamic>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,3 +53,71 @@ message BootstrapCommandRequest {
|
|||
message BootstrapCommandResponse {
|
||||
string bootstrap_command = 1;
|
||||
}
|
||||
|
||||
message JobClaimRequest {
|
||||
string runner_id = 1;
|
||||
string job_id = 2;
|
||||
string execution_id = 3;
|
||||
}
|
||||
|
||||
message JobClaimResponse {
|
||||
bool accepted = 1;
|
||||
string error_message = 2;
|
||||
string job_id = 3;
|
||||
string execution_id = 4;
|
||||
string state = 5;
|
||||
string runner_id = 6;
|
||||
}
|
||||
|
||||
message StepEventReport {
|
||||
int32 step_id = 1;
|
||||
int32 workflow_index = 2;
|
||||
string step_type = 3;
|
||||
string event = 4;
|
||||
string timestamp = 5;
|
||||
string command_id = 6;
|
||||
string command_type = 7;
|
||||
map<string, string> error = 8;
|
||||
}
|
||||
|
||||
message ExecutionReportRequest {
|
||||
string runner_id = 1;
|
||||
string job_id = 2;
|
||||
string execution_id = 3;
|
||||
bool success = 4;
|
||||
int32 exit_code = 5;
|
||||
string message = 6;
|
||||
repeated StepEventReport step_events = 7;
|
||||
}
|
||||
|
||||
message ExecutionReportResponse {
|
||||
bool accepted = 1;
|
||||
string error_message = 2;
|
||||
string job_id = 3;
|
||||
string execution_id = 4;
|
||||
string state = 5;
|
||||
string runner_id = 6;
|
||||
}
|
||||
|
||||
message LogAppendRequest {
|
||||
string runner_id = 1;
|
||||
string execution_id = 2;
|
||||
string line = 3;
|
||||
}
|
||||
|
||||
message LogAppendResponse {
|
||||
bool accepted = 1;
|
||||
string error_message = 2;
|
||||
}
|
||||
|
||||
message ArtifactReportRequest {
|
||||
string runner_id = 1;
|
||||
string execution_id = 2;
|
||||
string name = 3;
|
||||
string path = 4;
|
||||
}
|
||||
|
||||
message ArtifactReportResponse {
|
||||
bool accepted = 1;
|
||||
string error_message = 2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ func NewServerWithRegistryAndStore(addr string, registry *runnerregistry.Registr
|
|||
mux.HandleFunc("/api/v1/runners/{id}/disconnect", handleRunnerDisconnect(registry))
|
||||
mux.HandleFunc("/api/v1/runners/{id}", handleGetRunner(registry))
|
||||
mux.HandleFunc("/bootstrap/oto-agent.sh", handleServeBootstrapScript())
|
||||
mux.HandleFunc("/api/v1/", handleRouter(store, nil))
|
||||
mux.HandleFunc("/api/v1/", handleRouter(store, registry))
|
||||
|
||||
return &Server{
|
||||
httpServer: &http.Server{
|
||||
|
|
@ -453,6 +453,25 @@ func handleRouter(store *cicdstate.Store, registry *runnerregistry.Registry) htt
|
|||
http.NotFound(w, r)
|
||||
}
|
||||
|
||||
case "runners":
|
||||
if len(parts) < 2 {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
runnerID := parts[1]
|
||||
switch {
|
||||
case len(parts) == 4 && parts[2] == "jobs" && parts[3] == "claim" && r.Method == http.MethodPost:
|
||||
handleRunnerClaimJob(store, registry, runnerID)(w, r)
|
||||
case len(parts) == 5 && parts[2] == "executions" && parts[4] == "report" && r.Method == http.MethodPost:
|
||||
handleRunnerReportExecution(store, registry, runnerID, parts[3])(w, r)
|
||||
case len(parts) == 5 && parts[2] == "executions" && parts[4] == "logs" && r.Method == http.MethodPost:
|
||||
handleRunnerAppendLog(store, registry, runnerID, parts[3])(w, r)
|
||||
case len(parts) == 5 && parts[2] == "executions" && parts[4] == "artifacts" && r.Method == http.MethodPost:
|
||||
handleRunnerAppendArtifact(store, registry, runnerID, parts[3])(w, r)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
|
@ -669,6 +688,282 @@ func handleGetArtifacts(store *cicdstate.Store) http.HandlerFunc {
|
|||
}
|
||||
}
|
||||
|
||||
func handleRunnerClaimJob(store *cicdstate.Store, registry *runnerregistry.Registry, runnerID string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req otopb.JobClaimRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.JobClaimResponse{
|
||||
ErrorMessage: "invalid claim request",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if req.RunnerId == "" {
|
||||
req.RunnerId = runnerID
|
||||
} else if req.RunnerId != runnerID {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.JobClaimResponse{
|
||||
ErrorMessage: "runner id mismatch between path and body",
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := ensureRunnerKnown(registry, runnerID); err != nil {
|
||||
writeResponse(w, http.StatusNotFound, &otopb.JobClaimResponse{
|
||||
RunnerId: runnerID,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
jobID := strings.TrimSpace(req.GetJobId())
|
||||
execID := strings.TrimSpace(req.GetExecutionId())
|
||||
if jobID == "" || execID == "" {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.JobClaimResponse{
|
||||
RunnerId: runnerID,
|
||||
ErrorMessage: "job id and execution id are required",
|
||||
})
|
||||
return
|
||||
}
|
||||
job, err := store.GetJob(jobID)
|
||||
if err != nil {
|
||||
writeResponse(w, http.StatusNotFound, &otopb.JobClaimResponse{
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ErrorMessage: "job not found",
|
||||
})
|
||||
return
|
||||
}
|
||||
if job.State != cicdstate.StateQueued {
|
||||
writeResponse(w, http.StatusConflict, &otopb.JobClaimResponse{
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ErrorMessage: "job is not queued",
|
||||
State: job.State,
|
||||
})
|
||||
return
|
||||
}
|
||||
if _, err := store.CreateExecution(jobID, execID); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.JobClaimResponse{
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ExecutionId: execID,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := store.TransitionJob(jobID, cicdstate.StateRunning); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.JobClaimResponse{
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ExecutionId: execID,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := store.TransitionExecution(execID, cicdstate.StateRunning); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.JobClaimResponse{
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ExecutionId: execID,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
writeResponse(w, http.StatusOK, &otopb.JobClaimResponse{
|
||||
Accepted: true,
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ExecutionId: execID,
|
||||
State: cicdstate.StateRunning,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func handleRunnerReportExecution(store *cicdstate.Store, registry *runnerregistry.Registry, runnerID string, execID string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req otopb.ExecutionReportRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.ExecutionReportResponse{
|
||||
ErrorMessage: "invalid execution report request",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if req.RunnerId == "" {
|
||||
req.RunnerId = runnerID
|
||||
} else if req.RunnerId != runnerID {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.ExecutionReportResponse{
|
||||
ErrorMessage: "runner id mismatch between path and body",
|
||||
})
|
||||
return
|
||||
}
|
||||
if req.ExecutionId == "" {
|
||||
req.ExecutionId = execID
|
||||
} else if req.ExecutionId != execID {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.ExecutionReportResponse{
|
||||
ErrorMessage: "execution id mismatch between path and body",
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := ensureRunnerKnown(registry, runnerID); err != nil {
|
||||
writeResponse(w, http.StatusNotFound, &otopb.ExecutionReportResponse{
|
||||
RunnerId: runnerID,
|
||||
ExecutionId: execID,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
exec, err := store.GetExecution(execID)
|
||||
if err != nil {
|
||||
writeResponse(w, http.StatusNotFound, &otopb.ExecutionReportResponse{
|
||||
RunnerId: runnerID,
|
||||
ExecutionId: execID,
|
||||
ErrorMessage: "execution not found",
|
||||
})
|
||||
return
|
||||
}
|
||||
jobID := strings.TrimSpace(req.GetJobId())
|
||||
if jobID == "" {
|
||||
jobID = exec.JobID
|
||||
} else if jobID != exec.JobID {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.ExecutionReportResponse{
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ExecutionId: execID,
|
||||
ErrorMessage: "job id mismatch for execution",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
targetState := cicdstate.StateFailed
|
||||
if req.GetSuccess() {
|
||||
targetState = cicdstate.StateSucceeded
|
||||
}
|
||||
if err := store.TransitionExecution(execID, targetState); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.ExecutionReportResponse{
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ExecutionId: execID,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := store.TransitionJob(jobID, targetState); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.ExecutionReportResponse{
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ExecutionId: execID,
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
if strings.TrimSpace(req.GetMessage()) != "" {
|
||||
_ = store.AppendLog(execID, req.GetMessage())
|
||||
}
|
||||
|
||||
writeResponse(w, http.StatusOK, &otopb.ExecutionReportResponse{
|
||||
Accepted: true,
|
||||
RunnerId: runnerID,
|
||||
JobId: jobID,
|
||||
ExecutionId: execID,
|
||||
State: targetState,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func handleRunnerAppendLog(store *cicdstate.Store, registry *runnerregistry.Registry, runnerID string, execID string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req otopb.LogAppendRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.LogAppendResponse{
|
||||
ErrorMessage: "invalid log append request",
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := normalizeRunnerExecutionRequest(registry, runnerID, execID, req.GetRunnerId(), req.GetExecutionId()); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.LogAppendResponse{
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
line := strings.TrimSpace(req.GetLine())
|
||||
if line == "" {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.LogAppendResponse{
|
||||
ErrorMessage: "line is required",
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := store.AppendLog(execID, line); err != nil {
|
||||
writeResponse(w, http.StatusNotFound, &otopb.LogAppendResponse{
|
||||
ErrorMessage: "execution not found",
|
||||
})
|
||||
return
|
||||
}
|
||||
writeResponse(w, http.StatusCreated, &otopb.LogAppendResponse{
|
||||
Accepted: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func handleRunnerAppendArtifact(store *cicdstate.Store, registry *runnerregistry.Registry, runnerID string, execID string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var req otopb.ArtifactReportRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.ArtifactReportResponse{
|
||||
ErrorMessage: "invalid artifact report request",
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := normalizeRunnerExecutionRequest(registry, runnerID, execID, req.GetRunnerId(), req.GetExecutionId()); err != nil {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.ArtifactReportResponse{
|
||||
ErrorMessage: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
name := strings.TrimSpace(req.GetName())
|
||||
path := strings.TrimSpace(req.GetPath())
|
||||
if name == "" || path == "" {
|
||||
writeResponse(w, http.StatusBadRequest, &otopb.ArtifactReportResponse{
|
||||
ErrorMessage: "name and path are required",
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := store.AppendArtifact(execID, name, path); err != nil {
|
||||
writeResponse(w, http.StatusNotFound, &otopb.ArtifactReportResponse{
|
||||
ErrorMessage: "execution not found",
|
||||
})
|
||||
return
|
||||
}
|
||||
writeResponse(w, http.StatusCreated, &otopb.ArtifactReportResponse{
|
||||
Accepted: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeRunnerExecutionRequest(registry *runnerregistry.Registry, runnerID string, execID string, bodyRunnerID string, bodyExecID string) error {
|
||||
if bodyRunnerID != "" && bodyRunnerID != runnerID {
|
||||
return fmt.Errorf("runner id mismatch between path and body")
|
||||
}
|
||||
if bodyExecID != "" && bodyExecID != execID {
|
||||
return fmt.Errorf("execution id mismatch between path and body")
|
||||
}
|
||||
return ensureRunnerKnown(registry, runnerID)
|
||||
}
|
||||
|
||||
func ensureRunnerKnown(registry *runnerregistry.Registry, runnerID string) error {
|
||||
if strings.TrimSpace(runnerID) == "" {
|
||||
return fmt.Errorf("missing runner id")
|
||||
}
|
||||
if registry == nil {
|
||||
return nil
|
||||
}
|
||||
if _, ok := registry.Snapshot(runnerID); !ok {
|
||||
return fmt.Errorf("runner not found")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- JSON helpers ---
|
||||
|
||||
type jobResponse struct {
|
||||
|
|
|
|||
|
|
@ -723,3 +723,132 @@ func TestHandleCicdNotFound(t *testing.T) {
|
|||
t.Fatalf("unknown path = %v, want %v", rr.Code, http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleRunnerCicdClaimReportLogsAndArtifacts(t *testing.T) {
|
||||
store := cicdstate.NewStore()
|
||||
registry := runnerregistry.New()
|
||||
registry.Register(&otopb.RegisterRunnerRequest{
|
||||
EnrollmentToken: "token-123",
|
||||
RunnerId: "runner-123",
|
||||
ProtocolVersion: "oto.runner.v1",
|
||||
})
|
||||
if _, err := store.CreateJob("job-1", "build"); err != nil {
|
||||
t.Fatalf("CreateJob failed: %v", err)
|
||||
}
|
||||
|
||||
claimBody := bytes.NewBufferString(`{
|
||||
"runner_id":"runner-123",
|
||||
"job_id":"job-1",
|
||||
"execution_id":"exec-1"
|
||||
}`)
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/v1/runners/runner-123/jobs/claim", claimBody)
|
||||
rr := httptest.NewRecorder()
|
||||
handleRouter(store, registry)(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("claim status = %v, want %v; body=%s", rr.Code, http.StatusOK, rr.Body.String())
|
||||
}
|
||||
var claim otopb.JobClaimResponse
|
||||
if err := json.Unmarshal(rr.Body.Bytes(), &claim); err != nil {
|
||||
t.Fatalf("decode claim response: %v", err)
|
||||
}
|
||||
if !claim.GetAccepted() || claim.GetState() != cicdstate.StateRunning {
|
||||
t.Fatalf("claim response = %+v, want accepted running", claim)
|
||||
}
|
||||
|
||||
job, err := store.GetJob("job-1")
|
||||
if err != nil {
|
||||
t.Fatalf("GetJob after claim failed: %v", err)
|
||||
}
|
||||
if job.State != cicdstate.StateRunning || job.ExecutionID != "exec-1" {
|
||||
t.Fatalf("job after claim = %+v", job)
|
||||
}
|
||||
|
||||
logBody := bytes.NewBufferString(`{
|
||||
"runner_id":"runner-123",
|
||||
"execution_id":"exec-1",
|
||||
"line":"build started"
|
||||
}`)
|
||||
req = httptest.NewRequest(http.MethodPost, "/api/v1/runners/runner-123/executions/exec-1/logs", logBody)
|
||||
rr = httptest.NewRecorder()
|
||||
handleRouter(store, registry)(rr, req)
|
||||
if rr.Code != http.StatusCreated {
|
||||
t.Fatalf("append log status = %v, want %v; body=%s", rr.Code, http.StatusCreated, rr.Body.String())
|
||||
}
|
||||
|
||||
artifactBody := bytes.NewBufferString(`{
|
||||
"runner_id":"runner-123",
|
||||
"execution_id":"exec-1",
|
||||
"name":"binary",
|
||||
"path":"/dist/app"
|
||||
}`)
|
||||
req = httptest.NewRequest(http.MethodPost, "/api/v1/runners/runner-123/executions/exec-1/artifacts", artifactBody)
|
||||
rr = httptest.NewRecorder()
|
||||
handleRouter(store, registry)(rr, req)
|
||||
if rr.Code != http.StatusCreated {
|
||||
t.Fatalf("append artifact status = %v, want %v; body=%s", rr.Code, http.StatusCreated, rr.Body.String())
|
||||
}
|
||||
|
||||
reportBody := bytes.NewBufferString(`{
|
||||
"runner_id":"runner-123",
|
||||
"job_id":"job-1",
|
||||
"execution_id":"exec-1",
|
||||
"success":true,
|
||||
"exit_code":0,
|
||||
"message":"Build completed successfully.",
|
||||
"step_events":[{"event":"completed"}]
|
||||
}`)
|
||||
req = httptest.NewRequest(http.MethodPost, "/api/v1/runners/runner-123/executions/exec-1/report", reportBody)
|
||||
rr = httptest.NewRecorder()
|
||||
handleRouter(store, registry)(rr, req)
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("report status = %v, want %v; body=%s", rr.Code, http.StatusOK, rr.Body.String())
|
||||
}
|
||||
var report otopb.ExecutionReportResponse
|
||||
if err := json.Unmarshal(rr.Body.Bytes(), &report); err != nil {
|
||||
t.Fatalf("decode report response: %v", err)
|
||||
}
|
||||
if !report.GetAccepted() || report.GetState() != cicdstate.StateSucceeded {
|
||||
t.Fatalf("report response = %+v, want accepted succeeded", report)
|
||||
}
|
||||
|
||||
exec, err := store.GetExecution("exec-1")
|
||||
if err != nil {
|
||||
t.Fatalf("GetExecution after report failed: %v", err)
|
||||
}
|
||||
if exec.State != cicdstate.StateSucceeded {
|
||||
t.Fatalf("execution state = %q, want %q", exec.State, cicdstate.StateSucceeded)
|
||||
}
|
||||
if len(exec.Logs) != 2 {
|
||||
t.Fatalf("log count = %d, want explicit log plus report message", len(exec.Logs))
|
||||
}
|
||||
if len(exec.Artifacts) != 1 || exec.Artifacts[0].Name != "binary" {
|
||||
t.Fatalf("artifacts = %+v, want binary artifact", exec.Artifacts)
|
||||
}
|
||||
|
||||
job, err = store.GetJob("job-1")
|
||||
if err != nil {
|
||||
t.Fatalf("GetJob after report failed: %v", err)
|
||||
}
|
||||
if job.State != cicdstate.StateSucceeded {
|
||||
t.Fatalf("job state = %q, want %q", job.State, cicdstate.StateSucceeded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleRunnerCicdRejectsUnknownRunner(t *testing.T) {
|
||||
store := cicdstate.NewStore()
|
||||
if _, err := store.CreateJob("job-1", "build"); err != nil {
|
||||
t.Fatalf("CreateJob failed: %v", err)
|
||||
}
|
||||
|
||||
body := bytes.NewBufferString(`{
|
||||
"runner_id":"missing-runner",
|
||||
"job_id":"job-1",
|
||||
"execution_id":"exec-1"
|
||||
}`)
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/v1/runners/missing-runner/jobs/claim", body)
|
||||
rr := httptest.NewRecorder()
|
||||
handleRouter(store, runnerregistry.New())(rr, req)
|
||||
if rr.Code != http.StatusNotFound {
|
||||
t.Fatalf("status = %v, want %v; body=%s", rr.Code, http.StatusNotFound, rr.Body.String())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -518,6 +518,658 @@ func (x *BootstrapCommandResponse) GetBootstrapCommand() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
type JobClaimRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
|
||||
JobId string `protobuf:"bytes,2,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
|
||||
ExecutionId string `protobuf:"bytes,3,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *JobClaimRequest) Reset() {
|
||||
*x = JobClaimRequest{}
|
||||
mi := &file_oto_runner_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *JobClaimRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*JobClaimRequest) ProtoMessage() {}
|
||||
|
||||
func (x *JobClaimRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_oto_runner_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use JobClaimRequest.ProtoReflect.Descriptor instead.
|
||||
func (*JobClaimRequest) Descriptor() ([]byte, []int) {
|
||||
return file_oto_runner_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *JobClaimRequest) GetRunnerId() string {
|
||||
if x != nil {
|
||||
return x.RunnerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *JobClaimRequest) GetJobId() string {
|
||||
if x != nil {
|
||||
return x.JobId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *JobClaimRequest) GetExecutionId() string {
|
||||
if x != nil {
|
||||
return x.ExecutionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type JobClaimResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"`
|
||||
ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"`
|
||||
JobId string `protobuf:"bytes,3,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
|
||||
ExecutionId string `protobuf:"bytes,4,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
|
||||
State string `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"`
|
||||
RunnerId string `protobuf:"bytes,6,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *JobClaimResponse) Reset() {
|
||||
*x = JobClaimResponse{}
|
||||
mi := &file_oto_runner_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *JobClaimResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*JobClaimResponse) ProtoMessage() {}
|
||||
|
||||
func (x *JobClaimResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_oto_runner_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use JobClaimResponse.ProtoReflect.Descriptor instead.
|
||||
func (*JobClaimResponse) Descriptor() ([]byte, []int) {
|
||||
return file_oto_runner_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *JobClaimResponse) GetAccepted() bool {
|
||||
if x != nil {
|
||||
return x.Accepted
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *JobClaimResponse) GetErrorMessage() string {
|
||||
if x != nil {
|
||||
return x.ErrorMessage
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *JobClaimResponse) GetJobId() string {
|
||||
if x != nil {
|
||||
return x.JobId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *JobClaimResponse) GetExecutionId() string {
|
||||
if x != nil {
|
||||
return x.ExecutionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *JobClaimResponse) GetState() string {
|
||||
if x != nil {
|
||||
return x.State
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *JobClaimResponse) GetRunnerId() string {
|
||||
if x != nil {
|
||||
return x.RunnerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type StepEventReport struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
StepId int32 `protobuf:"varint,1,opt,name=step_id,json=stepId,proto3" json:"step_id,omitempty"`
|
||||
WorkflowIndex int32 `protobuf:"varint,2,opt,name=workflow_index,json=workflowIndex,proto3" json:"workflow_index,omitempty"`
|
||||
StepType string `protobuf:"bytes,3,opt,name=step_type,json=stepType,proto3" json:"step_type,omitempty"`
|
||||
Event string `protobuf:"bytes,4,opt,name=event,proto3" json:"event,omitempty"`
|
||||
Timestamp string `protobuf:"bytes,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
CommandId string `protobuf:"bytes,6,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"`
|
||||
CommandType string `protobuf:"bytes,7,opt,name=command_type,json=commandType,proto3" json:"command_type,omitempty"`
|
||||
Error map[string]string `protobuf:"bytes,8,rep,name=error,proto3" json:"error,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *StepEventReport) Reset() {
|
||||
*x = StepEventReport{}
|
||||
mi := &file_oto_runner_proto_msgTypes[10]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *StepEventReport) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*StepEventReport) ProtoMessage() {}
|
||||
|
||||
func (x *StepEventReport) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_oto_runner_proto_msgTypes[10]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use StepEventReport.ProtoReflect.Descriptor instead.
|
||||
func (*StepEventReport) Descriptor() ([]byte, []int) {
|
||||
return file_oto_runner_proto_rawDescGZIP(), []int{10}
|
||||
}
|
||||
|
||||
func (x *StepEventReport) GetStepId() int32 {
|
||||
if x != nil {
|
||||
return x.StepId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *StepEventReport) GetWorkflowIndex() int32 {
|
||||
if x != nil {
|
||||
return x.WorkflowIndex
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *StepEventReport) GetStepType() string {
|
||||
if x != nil {
|
||||
return x.StepType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StepEventReport) GetEvent() string {
|
||||
if x != nil {
|
||||
return x.Event
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StepEventReport) GetTimestamp() string {
|
||||
if x != nil {
|
||||
return x.Timestamp
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StepEventReport) GetCommandId() string {
|
||||
if x != nil {
|
||||
return x.CommandId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StepEventReport) GetCommandType() string {
|
||||
if x != nil {
|
||||
return x.CommandType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *StepEventReport) GetError() map[string]string {
|
||||
if x != nil {
|
||||
return x.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ExecutionReportRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
|
||||
JobId string `protobuf:"bytes,2,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
|
||||
ExecutionId string `protobuf:"bytes,3,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
|
||||
Success bool `protobuf:"varint,4,opt,name=success,proto3" json:"success,omitempty"`
|
||||
ExitCode int32 `protobuf:"varint,5,opt,name=exit_code,json=exitCode,proto3" json:"exit_code,omitempty"`
|
||||
Message string `protobuf:"bytes,6,opt,name=message,proto3" json:"message,omitempty"`
|
||||
StepEvents []*StepEventReport `protobuf:"bytes,7,rep,name=step_events,json=stepEvents,proto3" json:"step_events,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ExecutionReportRequest) Reset() {
|
||||
*x = ExecutionReportRequest{}
|
||||
mi := &file_oto_runner_proto_msgTypes[11]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ExecutionReportRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ExecutionReportRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ExecutionReportRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_oto_runner_proto_msgTypes[11]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ExecutionReportRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ExecutionReportRequest) Descriptor() ([]byte, []int) {
|
||||
return file_oto_runner_proto_rawDescGZIP(), []int{11}
|
||||
}
|
||||
|
||||
func (x *ExecutionReportRequest) GetRunnerId() string {
|
||||
if x != nil {
|
||||
return x.RunnerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExecutionReportRequest) GetJobId() string {
|
||||
if x != nil {
|
||||
return x.JobId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExecutionReportRequest) GetExecutionId() string {
|
||||
if x != nil {
|
||||
return x.ExecutionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExecutionReportRequest) GetSuccess() bool {
|
||||
if x != nil {
|
||||
return x.Success
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *ExecutionReportRequest) GetExitCode() int32 {
|
||||
if x != nil {
|
||||
return x.ExitCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ExecutionReportRequest) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExecutionReportRequest) GetStepEvents() []*StepEventReport {
|
||||
if x != nil {
|
||||
return x.StepEvents
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ExecutionReportResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"`
|
||||
ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"`
|
||||
JobId string `protobuf:"bytes,3,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
|
||||
ExecutionId string `protobuf:"bytes,4,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
|
||||
State string `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"`
|
||||
RunnerId string `protobuf:"bytes,6,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ExecutionReportResponse) Reset() {
|
||||
*x = ExecutionReportResponse{}
|
||||
mi := &file_oto_runner_proto_msgTypes[12]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ExecutionReportResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ExecutionReportResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ExecutionReportResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_oto_runner_proto_msgTypes[12]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ExecutionReportResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ExecutionReportResponse) Descriptor() ([]byte, []int) {
|
||||
return file_oto_runner_proto_rawDescGZIP(), []int{12}
|
||||
}
|
||||
|
||||
func (x *ExecutionReportResponse) GetAccepted() bool {
|
||||
if x != nil {
|
||||
return x.Accepted
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *ExecutionReportResponse) GetErrorMessage() string {
|
||||
if x != nil {
|
||||
return x.ErrorMessage
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExecutionReportResponse) GetJobId() string {
|
||||
if x != nil {
|
||||
return x.JobId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExecutionReportResponse) GetExecutionId() string {
|
||||
if x != nil {
|
||||
return x.ExecutionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExecutionReportResponse) GetState() string {
|
||||
if x != nil {
|
||||
return x.State
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ExecutionReportResponse) GetRunnerId() string {
|
||||
if x != nil {
|
||||
return x.RunnerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type LogAppendRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
|
||||
ExecutionId string `protobuf:"bytes,2,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
|
||||
Line string `protobuf:"bytes,3,opt,name=line,proto3" json:"line,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *LogAppendRequest) Reset() {
|
||||
*x = LogAppendRequest{}
|
||||
mi := &file_oto_runner_proto_msgTypes[13]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *LogAppendRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*LogAppendRequest) ProtoMessage() {}
|
||||
|
||||
func (x *LogAppendRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_oto_runner_proto_msgTypes[13]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use LogAppendRequest.ProtoReflect.Descriptor instead.
|
||||
func (*LogAppendRequest) Descriptor() ([]byte, []int) {
|
||||
return file_oto_runner_proto_rawDescGZIP(), []int{13}
|
||||
}
|
||||
|
||||
func (x *LogAppendRequest) GetRunnerId() string {
|
||||
if x != nil {
|
||||
return x.RunnerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *LogAppendRequest) GetExecutionId() string {
|
||||
if x != nil {
|
||||
return x.ExecutionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *LogAppendRequest) GetLine() string {
|
||||
if x != nil {
|
||||
return x.Line
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type LogAppendResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"`
|
||||
ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *LogAppendResponse) Reset() {
|
||||
*x = LogAppendResponse{}
|
||||
mi := &file_oto_runner_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *LogAppendResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*LogAppendResponse) ProtoMessage() {}
|
||||
|
||||
func (x *LogAppendResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_oto_runner_proto_msgTypes[14]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use LogAppendResponse.ProtoReflect.Descriptor instead.
|
||||
func (*LogAppendResponse) Descriptor() ([]byte, []int) {
|
||||
return file_oto_runner_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
func (x *LogAppendResponse) GetAccepted() bool {
|
||||
if x != nil {
|
||||
return x.Accepted
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *LogAppendResponse) GetErrorMessage() string {
|
||||
if x != nil {
|
||||
return x.ErrorMessage
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ArtifactReportRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
RunnerId string `protobuf:"bytes,1,opt,name=runner_id,json=runnerId,proto3" json:"runner_id,omitempty"`
|
||||
ExecutionId string `protobuf:"bytes,2,opt,name=execution_id,json=executionId,proto3" json:"execution_id,omitempty"`
|
||||
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Path string `protobuf:"bytes,4,opt,name=path,proto3" json:"path,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ArtifactReportRequest) Reset() {
|
||||
*x = ArtifactReportRequest{}
|
||||
mi := &file_oto_runner_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ArtifactReportRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ArtifactReportRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ArtifactReportRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_oto_runner_proto_msgTypes[15]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ArtifactReportRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ArtifactReportRequest) Descriptor() ([]byte, []int) {
|
||||
return file_oto_runner_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *ArtifactReportRequest) GetRunnerId() string {
|
||||
if x != nil {
|
||||
return x.RunnerId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ArtifactReportRequest) GetExecutionId() string {
|
||||
if x != nil {
|
||||
return x.ExecutionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ArtifactReportRequest) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ArtifactReportRequest) GetPath() string {
|
||||
if x != nil {
|
||||
return x.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ArtifactReportResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Accepted bool `protobuf:"varint,1,opt,name=accepted,proto3" json:"accepted,omitempty"`
|
||||
ErrorMessage string `protobuf:"bytes,2,opt,name=error_message,json=errorMessage,proto3" json:"error_message,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ArtifactReportResponse) Reset() {
|
||||
*x = ArtifactReportResponse{}
|
||||
mi := &file_oto_runner_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ArtifactReportResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ArtifactReportResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ArtifactReportResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_oto_runner_proto_msgTypes[16]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ArtifactReportResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ArtifactReportResponse) Descriptor() ([]byte, []int) {
|
||||
return file_oto_runner_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
func (x *ArtifactReportResponse) GetAccepted() bool {
|
||||
if x != nil {
|
||||
return x.Accepted
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *ArtifactReportResponse) GetErrorMessage() string {
|
||||
if x != nil {
|
||||
return x.ErrorMessage
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_oto_runner_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_oto_runner_proto_rawDesc = "" +
|
||||
|
|
@ -552,7 +1204,63 @@ const file_oto_runner_proto_rawDesc = "" +
|
|||
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12)\n" +
|
||||
"\x10enrollment_token\x18\x02 \x01(\tR\x0fenrollmentToken\"G\n" +
|
||||
"\x18BootstrapCommandResponse\x12+\n" +
|
||||
"\x11bootstrap_command\x18\x01 \x01(\tR\x10bootstrapCommand*q\n" +
|
||||
"\x11bootstrap_command\x18\x01 \x01(\tR\x10bootstrapCommand\"h\n" +
|
||||
"\x0fJobClaimRequest\x12\x1b\n" +
|
||||
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12\x15\n" +
|
||||
"\x06job_id\x18\x02 \x01(\tR\x05jobId\x12!\n" +
|
||||
"\fexecution_id\x18\x03 \x01(\tR\vexecutionId\"\xc0\x01\n" +
|
||||
"\x10JobClaimResponse\x12\x1a\n" +
|
||||
"\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" +
|
||||
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\x12\x15\n" +
|
||||
"\x06job_id\x18\x03 \x01(\tR\x05jobId\x12!\n" +
|
||||
"\fexecution_id\x18\x04 \x01(\tR\vexecutionId\x12\x14\n" +
|
||||
"\x05state\x18\x05 \x01(\tR\x05state\x12\x1b\n" +
|
||||
"\trunner_id\x18\x06 \x01(\tR\brunnerId\"\xdf\x02\n" +
|
||||
"\x0fStepEventReport\x12\x17\n" +
|
||||
"\astep_id\x18\x01 \x01(\x05R\x06stepId\x12%\n" +
|
||||
"\x0eworkflow_index\x18\x02 \x01(\x05R\rworkflowIndex\x12\x1b\n" +
|
||||
"\tstep_type\x18\x03 \x01(\tR\bstepType\x12\x14\n" +
|
||||
"\x05event\x18\x04 \x01(\tR\x05event\x12\x1c\n" +
|
||||
"\ttimestamp\x18\x05 \x01(\tR\ttimestamp\x12\x1d\n" +
|
||||
"\n" +
|
||||
"command_id\x18\x06 \x01(\tR\tcommandId\x12!\n" +
|
||||
"\fcommand_type\x18\a \x01(\tR\vcommandType\x12?\n" +
|
||||
"\x05error\x18\b \x03(\v2).oto.runner.v1.StepEventReport.ErrorEntryR\x05error\x1a8\n" +
|
||||
"\n" +
|
||||
"ErrorEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\x81\x02\n" +
|
||||
"\x16ExecutionReportRequest\x12\x1b\n" +
|
||||
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12\x15\n" +
|
||||
"\x06job_id\x18\x02 \x01(\tR\x05jobId\x12!\n" +
|
||||
"\fexecution_id\x18\x03 \x01(\tR\vexecutionId\x12\x18\n" +
|
||||
"\asuccess\x18\x04 \x01(\bR\asuccess\x12\x1b\n" +
|
||||
"\texit_code\x18\x05 \x01(\x05R\bexitCode\x12\x18\n" +
|
||||
"\amessage\x18\x06 \x01(\tR\amessage\x12?\n" +
|
||||
"\vstep_events\x18\a \x03(\v2\x1e.oto.runner.v1.StepEventReportR\n" +
|
||||
"stepEvents\"\xc7\x01\n" +
|
||||
"\x17ExecutionReportResponse\x12\x1a\n" +
|
||||
"\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" +
|
||||
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\x12\x15\n" +
|
||||
"\x06job_id\x18\x03 \x01(\tR\x05jobId\x12!\n" +
|
||||
"\fexecution_id\x18\x04 \x01(\tR\vexecutionId\x12\x14\n" +
|
||||
"\x05state\x18\x05 \x01(\tR\x05state\x12\x1b\n" +
|
||||
"\trunner_id\x18\x06 \x01(\tR\brunnerId\"f\n" +
|
||||
"\x10LogAppendRequest\x12\x1b\n" +
|
||||
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12!\n" +
|
||||
"\fexecution_id\x18\x02 \x01(\tR\vexecutionId\x12\x12\n" +
|
||||
"\x04line\x18\x03 \x01(\tR\x04line\"T\n" +
|
||||
"\x11LogAppendResponse\x12\x1a\n" +
|
||||
"\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" +
|
||||
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage\"\x7f\n" +
|
||||
"\x15ArtifactReportRequest\x12\x1b\n" +
|
||||
"\trunner_id\x18\x01 \x01(\tR\brunnerId\x12!\n" +
|
||||
"\fexecution_id\x18\x02 \x01(\tR\vexecutionId\x12\x12\n" +
|
||||
"\x04name\x18\x03 \x01(\tR\x04name\x12\x12\n" +
|
||||
"\x04path\x18\x04 \x01(\tR\x04path\"Y\n" +
|
||||
"\x16ArtifactReportResponse\x12\x1a\n" +
|
||||
"\baccepted\x18\x01 \x01(\bR\baccepted\x12#\n" +
|
||||
"\rerror_message\x18\x02 \x01(\tR\ferrorMessage*q\n" +
|
||||
"\x0fHeartbeatStatus\x12 \n" +
|
||||
"\x1cHEARTBEAT_STATUS_UNSPECIFIED\x10\x00\x12\x1c\n" +
|
||||
"\x18HEARTBEAT_STATUS_HEALTHY\x10\x01\x12\x1e\n" +
|
||||
|
|
@ -571,7 +1279,7 @@ func file_oto_runner_proto_rawDescGZIP() []byte {
|
|||
}
|
||||
|
||||
var file_oto_runner_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_oto_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 8)
|
||||
var file_oto_runner_proto_msgTypes = make([]protoimpl.MessageInfo, 18)
|
||||
var file_oto_runner_proto_goTypes = []any{
|
||||
(HeartbeatStatus)(0), // 0: oto.runner.v1.HeartbeatStatus
|
||||
(*RunnerCapability)(nil), // 1: oto.runner.v1.RunnerCapability
|
||||
|
|
@ -582,16 +1290,28 @@ var file_oto_runner_proto_goTypes = []any{
|
|||
(*HeartbeatResponse)(nil), // 6: oto.runner.v1.HeartbeatResponse
|
||||
(*BootstrapCommandRequest)(nil), // 7: oto.runner.v1.BootstrapCommandRequest
|
||||
(*BootstrapCommandResponse)(nil), // 8: oto.runner.v1.BootstrapCommandResponse
|
||||
(*JobClaimRequest)(nil), // 9: oto.runner.v1.JobClaimRequest
|
||||
(*JobClaimResponse)(nil), // 10: oto.runner.v1.JobClaimResponse
|
||||
(*StepEventReport)(nil), // 11: oto.runner.v1.StepEventReport
|
||||
(*ExecutionReportRequest)(nil), // 12: oto.runner.v1.ExecutionReportRequest
|
||||
(*ExecutionReportResponse)(nil), // 13: oto.runner.v1.ExecutionReportResponse
|
||||
(*LogAppendRequest)(nil), // 14: oto.runner.v1.LogAppendRequest
|
||||
(*LogAppendResponse)(nil), // 15: oto.runner.v1.LogAppendResponse
|
||||
(*ArtifactReportRequest)(nil), // 16: oto.runner.v1.ArtifactReportRequest
|
||||
(*ArtifactReportResponse)(nil), // 17: oto.runner.v1.ArtifactReportResponse
|
||||
nil, // 18: oto.runner.v1.StepEventReport.ErrorEntry
|
||||
}
|
||||
var file_oto_runner_proto_depIdxs = []int32{
|
||||
1, // 0: oto.runner.v1.RegisterRunnerRequest.capability:type_name -> oto.runner.v1.RunnerCapability
|
||||
2, // 1: oto.runner.v1.RegisterRunnerRequest.command_catalog:type_name -> oto.runner.v1.CommandCatalogSummary
|
||||
0, // 2: oto.runner.v1.HeartbeatRequest.status:type_name -> oto.runner.v1.HeartbeatStatus
|
||||
3, // [3:3] is the sub-list for method output_type
|
||||
3, // [3:3] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
1, // 0: oto.runner.v1.RegisterRunnerRequest.capability:type_name -> oto.runner.v1.RunnerCapability
|
||||
2, // 1: oto.runner.v1.RegisterRunnerRequest.command_catalog:type_name -> oto.runner.v1.CommandCatalogSummary
|
||||
0, // 2: oto.runner.v1.HeartbeatRequest.status:type_name -> oto.runner.v1.HeartbeatStatus
|
||||
18, // 3: oto.runner.v1.StepEventReport.error:type_name -> oto.runner.v1.StepEventReport.ErrorEntry
|
||||
11, // 4: oto.runner.v1.ExecutionReportRequest.step_events:type_name -> oto.runner.v1.StepEventReport
|
||||
5, // [5:5] is the sub-list for method output_type
|
||||
5, // [5:5] is the sub-list for method input_type
|
||||
5, // [5:5] is the sub-list for extension type_name
|
||||
5, // [5:5] is the sub-list for extension extendee
|
||||
0, // [0:5] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_oto_runner_proto_init() }
|
||||
|
|
@ -605,7 +1325,7 @@ func file_oto_runner_proto_init() {
|
|||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_oto_runner_proto_rawDesc), len(file_oto_runner_proto_rawDesc)),
|
||||
NumEnums: 1,
|
||||
NumMessages: 8,
|
||||
NumMessages: 18,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue