Skip to content

Commit 7766774

Browse files
committed
wip
Signed-off-by: npolshakova <nina.polshakova@solo.io>
1 parent a0d689b commit 7766774

17 files changed

Lines changed: 1792 additions & 137 deletions

File tree

cmd/ateapi/internal/controlapi/workflow_resume.go

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -171,24 +171,7 @@ func (s *CallAteletRestoreStep) Execute(ctx context.Context, input *ResumeInput,
171171
}
172172
client := ateletpb.NewAteomHerderClient(ateletConn)
173173

174-
workloadSpec := &ateletpb.WorkloadSpec{
175-
PauseImage: state.ActorTemplate.Spec.PauseImage,
176-
}
177-
for _, ctr := range state.ActorTemplate.Spec.Containers {
178-
ateletCtr := &ateletpb.Container{
179-
Name: ctr.Name,
180-
Image: ctr.Image,
181-
Command: ctr.Command,
182-
}
183-
for _, env := range ctr.Env {
184-
ateletEnv := &ateletpb.EnvEntry{
185-
Name: env.Name,
186-
Value: env.Value,
187-
}
188-
ateletCtr.Env = append(ateletCtr.Env, ateletEnv)
189-
}
190-
workloadSpec.Containers = append(workloadSpec.Containers, ateletCtr)
191-
}
174+
workloadSpec := buildAteletWorkloadSpec(state.ActorTemplate)
192175

193176
runscCfg := &ateletpb.RunscConfig{}
194177
if state.ActorTemplate.Spec.Runsc.AMD64 != nil {

cmd/ateapi/internal/controlapi/workflow_suspend.go

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -142,25 +142,8 @@ func (s *CallAteletSuspendStep) Execute(ctx context.Context, input *SuspendInput
142142
ActorTemplateName: state.Actor.GetActorTemplateName(),
143143
ActorId: state.Actor.GetActorId(),
144144
Runsc: runscCfg,
145-
Spec: &ateletpb.WorkloadSpec{
146-
PauseImage: state.ActorTemplate.Spec.PauseImage,
147-
},
148-
SnapshotUriPrefix: state.Actor.GetInProgressSnapshot(),
149-
}
150-
for _, ctr := range state.ActorTemplate.Spec.Containers {
151-
ateletCtr := &ateletpb.Container{
152-
Name: ctr.Name,
153-
Image: ctr.Image,
154-
Command: ctr.Command,
155-
}
156-
for _, env := range ctr.Env {
157-
ateletEnv := &ateletpb.EnvEntry{
158-
Name: env.Name,
159-
Value: env.Value,
160-
}
161-
ateletCtr.Env = append(ateletCtr.Env, ateletEnv)
162-
}
163-
req.Spec.Containers = append(req.Spec.Containers, ateletCtr)
145+
Spec: buildAteletWorkloadSpec(state.ActorTemplate),
146+
SnapshotUriPrefix: state.Actor.GetInProgressSnapshot(),
164147
}
165148
_, err = client.Checkpoint(ctx, req)
166149
if err != nil {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package controlapi
16+
17+
import (
18+
"github.com/agent-substrate/substrate/internal/proto/ateletpb"
19+
atev1alpha1 "github.com/agent-substrate/substrate/pkg/api/v1alpha1"
20+
)
21+
22+
func buildAteletWorkloadSpec(actorTemplate *atev1alpha1.ActorTemplate) *ateletpb.WorkloadSpec {
23+
workloadSpec := &ateletpb.WorkloadSpec{
24+
PauseImage: actorTemplate.Spec.PauseImage,
25+
EgressPolicy: buildAteletEgressPolicy(actorTemplate.Spec.EgressPolicy),
26+
}
27+
for _, ctr := range actorTemplate.Spec.Containers {
28+
ateletCtr := &ateletpb.Container{
29+
Name: ctr.Name,
30+
Image: ctr.Image,
31+
Command: ctr.Command,
32+
}
33+
for _, env := range ctr.Env {
34+
ateletCtr.Env = append(ateletCtr.Env, &ateletpb.EnvEntry{
35+
Name: env.Name,
36+
Value: env.Value,
37+
})
38+
}
39+
workloadSpec.Containers = append(workloadSpec.Containers, ateletCtr)
40+
}
41+
return workloadSpec
42+
}
43+
44+
func buildAteletEgressPolicy(policy *atev1alpha1.EgressPolicy) *ateletpb.EgressPolicy {
45+
if policy == nil {
46+
return nil
47+
}
48+
return &ateletpb.EgressPolicy{
49+
DefaultAction: string(policy.DefaultAction),
50+
Allow: buildAteletEgressPolicyRules(policy.Allow),
51+
Deny: buildAteletEgressPolicyRules(policy.Deny),
52+
}
53+
}
54+
55+
func buildAteletEgressPolicyRules(rules []atev1alpha1.EgressPolicyRule) []*ateletpb.EgressPolicyRule {
56+
out := make([]*ateletpb.EgressPolicyRule, 0, len(rules))
57+
for _, rule := range rules {
58+
outRule := &ateletpb.EgressPolicyRule{}
59+
for _, dest := range rule.To {
60+
outDest := &ateletpb.EgressPolicyDestination{Host: dest.Host}
61+
if dest.IPBlock != nil {
62+
outDest.Cidr = dest.IPBlock.CIDR
63+
}
64+
outRule.To = append(outRule.To, outDest)
65+
}
66+
for _, port := range rule.Ports {
67+
outRule.Ports = append(outRule.Ports, &ateletpb.EgressPort{
68+
Port: uint32(port.Port),
69+
Protocol: string(port.Protocol),
70+
})
71+
}
72+
out = append(out, outRule)
73+
}
74+
return out
75+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package controlapi
16+
17+
import (
18+
"testing"
19+
20+
corev1 "k8s.io/api/core/v1"
21+
22+
atev1alpha1 "github.com/agent-substrate/substrate/pkg/api/v1alpha1"
23+
)
24+
25+
func TestBuildAteletWorkloadSpecIncludesEgressPolicy(t *testing.T) {
26+
spec := buildAteletWorkloadSpec(&atev1alpha1.ActorTemplate{
27+
Spec: atev1alpha1.ActorTemplateSpec{
28+
PauseImage: "pause",
29+
Containers: []atev1alpha1.Container{
30+
{Name: "app", Image: "example/app"},
31+
},
32+
EgressPolicy: &atev1alpha1.EgressPolicy{
33+
DefaultAction: atev1alpha1.EgressPolicyActionDeny,
34+
Allow: []atev1alpha1.EgressPolicyRule{
35+
{
36+
To: []atev1alpha1.EgressPolicyDestination{
37+
{Host: "example.com"},
38+
{IPBlock: &atev1alpha1.EgressIPBlock{CIDR: "10.96.0.10/32"}},
39+
},
40+
Ports: []atev1alpha1.EgressPort{
41+
{Port: 443, Protocol: corev1.ProtocolTCP},
42+
},
43+
},
44+
},
45+
},
46+
},
47+
})
48+
49+
if got, want := spec.GetEgressPolicy().GetDefaultAction(), "Deny"; got != want {
50+
t.Fatalf("default action = %q, want %q", got, want)
51+
}
52+
allow := spec.GetEgressPolicy().GetAllow()
53+
if len(allow) != 1 {
54+
t.Fatalf("allow rule count = %d, want 1", len(allow))
55+
}
56+
if got, want := allow[0].GetTo()[0].GetHost(), "example.com"; got != want {
57+
t.Fatalf("host = %q, want %q", got, want)
58+
}
59+
if got, want := allow[0].GetTo()[1].GetCidr(), "10.96.0.10/32"; got != want {
60+
t.Fatalf("cidr = %q, want %q", got, want)
61+
}
62+
if got, want := allow[0].GetPorts()[0].GetProtocol(), "TCP"; got != want {
63+
t.Fatalf("protocol = %q, want %q", got, want)
64+
}
65+
}

cmd/atelet/main.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,13 +514,47 @@ func (s *AteomHerder) dialAteom(ctx context.Context, namespace, name string) (at
514514
// buildAteomWorkloadSpec projects the atelet-facing workload spec onto
515515
// the ateom-facing one — currently just the container names.
516516
func buildAteomWorkloadSpec(spec *ateletpb.WorkloadSpec) *ateompb.WorkloadSpec {
517-
out := &ateompb.WorkloadSpec{}
517+
out := &ateompb.WorkloadSpec{
518+
EgressPolicy: buildAteomEgressPolicy(spec.GetEgressPolicy()),
519+
}
518520
for _, ctr := range spec.GetContainers() {
519521
out.Containers = append(out.Containers, &ateompb.Container{Name: ctr.GetName()})
520522
}
521523
return out
522524
}
523525

526+
func buildAteomEgressPolicy(policy *ateletpb.EgressPolicy) *ateompb.EgressPolicy {
527+
if policy == nil {
528+
return nil
529+
}
530+
return &ateompb.EgressPolicy{
531+
DefaultAction: policy.GetDefaultAction(),
532+
Allow: buildAteomEgressPolicyRules(policy.GetAllow()),
533+
Deny: buildAteomEgressPolicyRules(policy.GetDeny()),
534+
}
535+
}
536+
537+
func buildAteomEgressPolicyRules(rules []*ateletpb.EgressPolicyRule) []*ateompb.EgressPolicyRule {
538+
out := make([]*ateompb.EgressPolicyRule, 0, len(rules))
539+
for _, rule := range rules {
540+
outRule := &ateompb.EgressPolicyRule{}
541+
for _, dest := range rule.GetTo() {
542+
outRule.To = append(outRule.To, &ateompb.EgressPolicyDestination{
543+
Host: dest.GetHost(),
544+
Cidr: dest.GetCidr(),
545+
})
546+
}
547+
for _, port := range rule.GetPorts() {
548+
outRule.Ports = append(outRule.Ports, &ateompb.EgressPort{
549+
Port: port.GetPort(),
550+
Protocol: port.GetProtocol(),
551+
})
552+
}
553+
out = append(out, outRule)
554+
}
555+
return out
556+
}
557+
524558
// uploadIfExists uploads a local file to GCS (zstd-compressed) only if
525559
// the file is present. Missing files are silently skipped — used for
526560
// optional checkpoint side-files (pages.img, pages_meta.img).

cmd/atelet/main_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2026 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package main
16+
17+
import (
18+
"testing"
19+
20+
"github.com/agent-substrate/substrate/internal/proto/ateletpb"
21+
)
22+
23+
func TestBuildAteomWorkloadSpecIncludesEgressPolicy(t *testing.T) {
24+
spec := buildAteomWorkloadSpec(&ateletpb.WorkloadSpec{
25+
Containers: []*ateletpb.Container{{Name: "app"}},
26+
EgressPolicy: &ateletpb.EgressPolicy{
27+
DefaultAction: "Deny",
28+
Allow: []*ateletpb.EgressPolicyRule{
29+
{
30+
To: []*ateletpb.EgressPolicyDestination{
31+
{Host: "example.com"},
32+
},
33+
Ports: []*ateletpb.EgressPort{
34+
{Port: 443, Protocol: "TCP"},
35+
},
36+
},
37+
},
38+
},
39+
})
40+
41+
if got, want := spec.GetEgressPolicy().GetDefaultAction(), "Deny"; got != want {
42+
t.Fatalf("default action = %q, want %q", got, want)
43+
}
44+
if got, want := spec.GetEgressPolicy().GetAllow()[0].GetTo()[0].GetHost(), "example.com"; got != want {
45+
t.Fatalf("host = %q, want %q", got, want)
46+
}
47+
if got, want := spec.GetEgressPolicy().GetAllow()[0].GetPorts()[0].GetPort(), uint32(443); got != want {
48+
t.Fatalf("port = %d, want %d", got, want)
49+
}
50+
}

0 commit comments

Comments
 (0)