Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 51 additions & 5 deletions cmd/ateapi/internal/controlapi/workload_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,48 @@ import (
func workloadSpecFromActorTemplate(actorTemplate *atev1alpha1.ActorTemplate, actor *ateapipb.Actor) (*ateletpb.WorkloadSpec, error) {
workloadSpec := &ateletpb.WorkloadSpec{}

// add volumes
// Convert volumes to atelet's representation. ActorTemplate validation has
// already ensured that only one source is set.
for _, vol := range actorTemplate.Spec.Volumes {
// volume is durable-dir type
if vol.VolumeSource.DurableDir != nil {
switch {
case vol.VolumeSource.DurableDir != nil:
workloadSpec.Volumes = append(workloadSpec.Volumes, &ateletpb.Volume{
Name: vol.Name,
Type: ateletpb.VolumeType_VOLUME_TYPE_DURABLE_DIR,
Source: &ateletpb.Volume_DurableDir{
DurableDir: &ateletpb.DurableDirVolume{},
},
})

case vol.VolumeSource.SystemInfo != nil:
ateletSystemInfo := &ateletpb.SystemInfoVolume{}
for _, dataSource := range vol.VolumeSource.SystemInfo.DataSources {
switch {
case dataSource.ActorMetadata != nil:
actorMetadata := &ateletpb.ActorMetadataDataSource{}
for _, item := range dataSource.ActorMetadata.Items {
actorMetadata.Items = append(actorMetadata.Items, &ateletpb.ActorMetadataItem{
Field: toAteletActorMetadataField(item.Field),
Path: item.Path,
})
}
ateletSystemInfo.DataSources = append(ateletSystemInfo.DataSources, &ateletpb.SystemInfoDataSource{
DataSource: &ateletpb.SystemInfoDataSource_ActorMetadata{
ActorMetadata: actorMetadata,
},
})
default:
continue // Drop unrecognized data sources
}
}
workloadSpec.Volumes = append(workloadSpec.Volumes, &ateletpb.Volume{
Name: vol.Name,
Source: &ateletpb.Volume_SystemInfo{
SystemInfo: ateletSystemInfo,
},
})

default:
continue // Drop unrecognized volumes.
}
}

Expand Down Expand Up @@ -104,7 +135,6 @@ func appendExternalVolumes(workloadSpec *ateletpb.WorkloadSpec, template *atev1a
}
workloadSpec.Volumes = append(workloadSpec.Volumes, &ateletpb.Volume{
Name: vol.Name,
Type: ateletpb.VolumeType_VOLUME_TYPE_EXTERNAL,
Source: &ateletpb.Volume_External{
External: &ateletpb.ExternalVolumeSource{
StorageVolumeId: storageVolID,
Expand Down Expand Up @@ -132,6 +162,22 @@ func isVolumeMounted(volumeName string, template *atev1alpha1.ActorTemplate) boo
// toAteletReadyz projects the CRD readyz field onto the ateletpb wire type.
// Returns nil when the source is nil so containers without a probe stay
// unchanged on the wire.
// toAteletActorMetadataField projects the CRD field selector onto the atelet
// wire enum. Unknown values map to UNSPECIFIED, which atelet skips; CRD enum
// validation makes that unreachable for stored templates.
func toAteletActorMetadataField(in atev1alpha1.ActorMetadataField) ateletpb.ActorMetadataField {
switch in {
case atev1alpha1.ActorMetadataFieldName:
return ateletpb.ActorMetadataField_ACTOR_METADATA_FIELD_NAME
case atev1alpha1.ActorMetadataFieldAtespace:
return ateletpb.ActorMetadataField_ACTOR_METADATA_FIELD_ATESPACE
case atev1alpha1.ActorMetadataFieldUID:
return ateletpb.ActorMetadataField_ACTOR_METADATA_FIELD_UID
default:
return ateletpb.ActorMetadataField_ACTOR_METADATA_FIELD_UNSPECIFIED
}
}

func toAteletReadyz(in *atev1alpha1.ContainerReadyz) *ateletpb.Readyz {
if in == nil {
return nil
Expand Down
70 changes: 66 additions & 4 deletions cmd/ateapi/internal/controlapi/workload_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ func TestWorkloadSpecFromActorTemplate(t *testing.T) {
Volumes: []*ateletpb.Volume{
{
Name: "home",
Type: ateletpb.VolumeType_VOLUME_TYPE_DURABLE_DIR,
Source: &ateletpb.Volume_DurableDir{DurableDir: &ateletpb.DurableDirVolume{}},
},
},
Expand All @@ -71,6 +70,72 @@ func TestWorkloadSpecFromActorTemplate(t *testing.T) {
},
},
},
{
name: "converts SystemInfo volume with actorMetadata items",
template: &atev1alpha1.ActorTemplate{
ObjectMeta: metav1.ObjectMeta{Name: "tmpl1", Namespace: "agent-ns"},
Spec: atev1alpha1.ActorTemplateSpec{
Volumes: []atev1alpha1.Volume{
{
Name: "system-info",
VolumeSource: atev1alpha1.VolumeSource{
SystemInfo: &atev1alpha1.SystemInfoVolumeSource{
DataSources: []atev1alpha1.SystemInfoDataSource{
{ActorMetadata: &atev1alpha1.ActorMetadataDataSource{
Items: []atev1alpha1.ActorMetadataItem{
{Field: atev1alpha1.ActorMetadataFieldName, Path: "actor-name"},
{Field: atev1alpha1.ActorMetadataFieldAtespace, Path: "atespace"},
{Field: atev1alpha1.ActorMetadataFieldUID, Path: "identity/actor-uid"},
},
}},
},
},
},
},
},
Containers: []atev1alpha1.Container{
{
Name: "main",
Image: "main",
VolumeMounts: []atev1alpha1.VolumeMount{
{Name: "system-info", MountPath: "/run/ate"},
},
},
},
},
},
want: &ateletpb.WorkloadSpec{
Volumes: []*ateletpb.Volume{
{
Name: "system-info",
Source: &ateletpb.Volume_SystemInfo{
SystemInfo: &ateletpb.SystemInfoVolume{
DataSources: []*ateletpb.SystemInfoDataSource{
{DataSource: &ateletpb.SystemInfoDataSource_ActorMetadata{
ActorMetadata: &ateletpb.ActorMetadataDataSource{
Items: []*ateletpb.ActorMetadataItem{
{Field: ateletpb.ActorMetadataField_ACTOR_METADATA_FIELD_NAME, Path: "actor-name"},
{Field: ateletpb.ActorMetadataField_ACTOR_METADATA_FIELD_ATESPACE, Path: "atespace"},
{Field: ateletpb.ActorMetadataField_ACTOR_METADATA_FIELD_UID, Path: "identity/actor-uid"},
},
},
}},
},
},
},
},
},
Containers: []*ateletpb.Container{
{
Name: "main",
Image: "main",
VolumeMounts: []*ateletpb.VolumeMount{
{Name: "system-info", MountPath: "/run/ate"},
},
},
},
},
},
{
name: "skips non-DurableDir volumes",
template: &atev1alpha1.ActorTemplate{
Expand All @@ -95,7 +160,6 @@ func TestWorkloadSpecFromActorTemplate(t *testing.T) {
Volumes: []*ateletpb.Volume{
{
Name: "home",
Type: ateletpb.VolumeType_VOLUME_TYPE_DURABLE_DIR,
Source: &ateletpb.Volume_DurableDir{DurableDir: &ateletpb.DurableDirVolume{}},
},
},
Expand Down Expand Up @@ -127,7 +191,6 @@ func TestWorkloadSpecFromActorTemplate(t *testing.T) {
Volumes: []*ateletpb.Volume{
{
Name: "home",
Type: ateletpb.VolumeType_VOLUME_TYPE_DURABLE_DIR,
Source: &ateletpb.Volume_DurableDir{DurableDir: &ateletpb.DurableDirVolume{}},
},
},
Expand Down Expand Up @@ -308,7 +371,6 @@ func TestAppendExternalVolumes(t *testing.T) {
Volumes: []*ateletpb.Volume{
{
Name: "vol-1",
Type: ateletpb.VolumeType_VOLUME_TYPE_EXTERNAL,
Source: &ateletpb.Volume_External{
External: &ateletpb.ExternalVolumeSource{
StorageVolumeId: "vol-gce-pd-123",
Expand Down
53 changes: 53 additions & 0 deletions cmd/atelet/internal/third_party/atomicwriter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# third_party/atomicwriter

Kubelet's atomic writer, copied from the Kubernetes monorepo:

- **Upstream source:** `k8s.io/kubernetes/pkg/volume/util/`
(`atomic_writer.go`, `atomic_writer_linux.go`, `atomic_writer_unsupported.go`,
`atomic_writer_test.go`)
- **Delta last verified against:** [`kubernetes/kubernetes@52ba9013`](https://github.com/kubernetes/kubernetes/commit/52ba90138eb40cab0987dac73e05c838149bdd1c) (master, 2026-08-13)
- **License:** Apache-2.0; the upstream copyright headers are retained in every file.

Copied rather than imported to avoid importing the full Kubernetes dependency tree
into atelet.

## Local modifications

Every modified file carries a `// substrate:` marker below its license header;
`grep -rn "substrate:" .` from this directory lists the patched files. The
changes, by class:

1. Package renamed `util` → `atomicwriter`.
2. Kubernetes-internal dependencies dropped: `k8s.io/klog/v2`,
`k8s.io/apiserver/pkg/util/feature`, and `k8s.io/kubernetes/pkg/features`
(`k8s.io/apimachinery/pkg/util/sets` is kept — substrate already vendors it).
In the test file, `k8s.io/client-go/util/testing` is replaced by a local
`mkTmpdir` helper.
3. Logging converted from klog to `log/slog`, threading a `context.Context`
through `Write`, `pathsToRemove`, and `removeUserVisiblePaths` for
`slog.*Context`. The `logContext` field/constructor parameter this obsoletes
is removed: `NewAtomicWriter(targetDir, logContext)` →
`NewAtomicWriter(targetDir)`.
4. Error handling restyled: upstream's log-then-`return err` sites return
wrapped errors (`fmt.Errorf("while ...: %w", err)`) per substrate
convention; klog error logs that accompanied a `return` are dropped in
favor of the wrapped error.
5. Upstream's `ResolvesFsUser` helper (KEP-5936, feature-gate dependent) is
omitted; substrate does not use FsUser resolution.

## Maintenance rules

- Only mechanical adaptations (the classes above) belong in the
upstream-derived files. Anything behavioral goes in a separate,
substrate-owned file in this package (none exist today).
- When touching these files, keep the diff against upstream minimal and update
the modification list here if a new class of change is introduced.

## Re-syncing with upstream

1. Fetch the files listed above from `k8s.io/kubernetes` at the new commit.
2. Diff against this copy, ignoring the modification classes above
(the delta is ~80 lines; it is meant to stay readable by hand).
3. Apply upstream's changes, re-apply our classes to any new code, run
`go test ./cmd/atelet/internal/third_party/atomicwriter/`, and update the
"Delta last verified against" commit above.
Loading