Conversation
Test & Lint Summary
|
Update Summary
Test & Lint Summary
|
noa-lucent
left a comment
There was a problem hiding this comment.
The PR implements ListWorkloads/ListVolumes gRPC handlers and label propagation as specified in #17. The overall structure follows existing codebase patterns well. There is one major issue and several minor items to address:
Major:
extractRequestLabelsis computed twice perstartWorkloadcall (once inserver.ts, once insidestartWorkloadRequestToContainerOpts), creating redundancy and a divergence risk.
Minor:
- Missing test coverage for the new gRPC handlers,
ensureWorkloadVolumes,resolveVolumeName, and label merge precedence. - Duplicated container sorting comparator should be extracted.
ensureVolumesilently skips label application on existing volumes (Docker limitation) — worth documenting/logging.- The skip-when-no-labels logic in
ensureWorkloadVolumesis a subtle behavioral decision that should be documented.
| return callback(toServiceError(status.INVALID_ARGUMENT, 'main_container_required')); | ||
| } | ||
| try { | ||
| const requestLabels = extractRequestLabels(call.request); |
There was a problem hiding this comment.
[major] extractRequestLabels(call.request) is computed here, and then startWorkloadRequestToContainerOpts(call.request) at line 413 calls extractRequestLabels(request) again internally (line 306 in workload.grpc.ts). This means:
- The label extraction runs twice per
startWorkloadcall — redundant work. - Worse, if either call site is changed independently, the two label sets could diverge silently, leading to
ensureWorkloadVolumesusing different labels than the container itself.
Consider having startWorkloadRequestToContainerOpts accept the pre-computed labels as a parameter, or return the extracted labels alongside opts, so the extraction happens in a single place.
| const volumeName = resolveVolumeName(spec); | ||
| if (!volumeName || ensured.has(volumeName)) continue; | ||
| const volumeLabels = { ...baseLabels, ...(spec.labels ?? {}) }; | ||
| if (Object.keys(volumeLabels).length === 0) continue; |
There was a problem hiding this comment.
[minor] This skips ensureVolume when volumeLabels is empty. That means named volumes without any orchestrator-provided label.* properties won't be pre-created here — Docker will create them implicitly (without labels) when the container starts.
This is likely intentional (no labels → nothing useful to apply), but it's a subtle contract: a named volume that the orchestrator doesn't label will never appear in ListVolumes results. Worth a brief comment documenting the intent.
| all: options?.all ?? true, | ||
| filters: { label: [labelKey] }, | ||
| }); | ||
| const sorted = [...list].sort((a: Docker.ContainerInfo, b: Docker.ContainerInfo) => { |
There was a problem hiding this comment.
[minor] This sorting comparator is duplicated verbatim from findContainersByLabels (line 1004). Extract it into a named helper (e.g., sortContainersByCreatedThenId) to eliminate the duplication and make future changes to the ordering policy apply consistently.
| }; | ||
|
|
||
| const rebuilt = startWorkloadRequestToContainerOpts(request); | ||
|
|
There was a problem hiding this comment.
[minor] Good to see coverage for label.* extraction. However, this PR introduces several new behaviors that lack test coverage:
extractRequestLabelsmerging precedence: what happens whenrequest.labelsandlabel.*inadditionalPropertieshave overlapping keys?labels_json+label.*merge: the existinglabels_jsonpath now merges with request-level labels — the precedence should be tested.resolveVolumeName: edge cases (empty name, slashes, persistentName vs name fallback).ensureWorkloadVolumes: deduplication, NAMED-only filtering, skip-when-no-labels.listWorkloads/listVolumeshandlers: at minimum, unit-level tests with mockedContainerServiceto verify sidecar filtering and label key extraction.
Consider adding tests for these to avoid regressions in the reconciliation logic.
| await this.docker.createVolume({ Name: name, Labels: labels ?? {} }); | ||
| } catch (e: unknown) { | ||
| const sc = typeof e === 'object' && e && 'statusCode' in e ? (e as { statusCode?: number }).statusCode : undefined; | ||
| if (sc === 409) { |
There was a problem hiding this comment.
[minor] Note that if the volume already exists (409), labels are silently not applied since Docker doesn't support updating volume labels post-creation. This means if a volume was created earlier (e.g., by a previous workload without labels or with different labels), ListVolumes may not return the expected volume_key. Consider adding a log at debug level when hitting the 409 path to note that labels were not applied, so operators can diagnose reconciliation mismatches.
Summary
Testing
Closes #17