diff --git a/cmd/atelet/credentialbroker.go b/cmd/atelet/ateomsupport.go similarity index 67% rename from cmd/atelet/credentialbroker.go rename to cmd/atelet/ateomsupport.go index 85f1f72294..7f75db1cdf 100644 --- a/cmd/atelet/credentialbroker.go +++ b/cmd/atelet/ateomsupport.go @@ -18,6 +18,7 @@ import ( "context" "crypto/tls" "fmt" + "log/slog" "github.com/agent-substrate/substrate/internal/proto/ateletpb" "github.com/agent-substrate/substrate/internal/substratex509" @@ -28,12 +29,13 @@ import ( "google.golang.org/grpc/status" ) -type credentialBroker struct { - ateletpb.UnimplementedCredentialBrokerServer +type ateomSupportServer struct { + ateletpb.UnimplementedAteomSupportServer controlClient ateapipb.ControlClient + workers ateapipb.WorkerServiceClient } -func (b *credentialBroker) MintActorCertificate(ctx context.Context, req *ateletpb.MintActorCertificateRequest) (*ateletpb.MintActorCertificateResponse, error) { +func (b *ateomSupportServer) MintActorCertificate(ctx context.Context, req *ateletpb.MintActorCertificateRequest) (*ateletpb.MintActorCertificateResponse, error) { // Check which ateom is calling. _, err := authenticatedWorkerIdentity(ctx) if err != nil { @@ -92,3 +94,30 @@ func verifyClientOnSameNode(node *substratex509.PodIdentity) func(tls.Connection return nil } } + +// SetWorkerCapacity records what the calling worker says it has. +// +// It returns the control plane's error unwrapped so the caller retries: a +// worker reports once, so an accepted call is the only thing that puts +// capacity on the Worker, and a Worker record the syncer has not created yet +// is the ordinary reason for a first attempt to fail. +func (s *ateomSupportServer) SetWorkerCapacity(ctx context.Context, req *ateletpb.SetWorkerCapacityRequest) (*ateletpb.SetWorkerCapacityResponse, error) { + // Identity comes only from the mTLS certificate, never from the request: + // a worker can report its own capacity and no one else's. + workerIdentity, err := authenticatedWorkerIdentity(ctx) + if err != nil { + return nil, err + } + // Forwarded as reported: the worker speaks the vocabulary the control plane + // records, so there is nothing to translate. + if _, err := s.workers.SetWorkerCapacity(ctx, &ateapipb.SetWorkerCapacityRequest{ + // Workers are global-scoped and named by their pod UID. + Worker: &ateapipb.ObjectRef{Name: workerIdentity.PodUID}, + Capacity: req.GetCapacity(), + }); err != nil { + return nil, err + } + slog.InfoContext(ctx, "Recorded worker capacity", + slog.String("pod_uid", workerIdentity.PodUID), slog.Any("capacity", req.GetCapacity())) + return &ateletpb.SetWorkerCapacityResponse{}, nil +} diff --git a/cmd/atelet/workercapacity_test.go b/cmd/atelet/ateomsupport_test.go similarity index 62% rename from cmd/atelet/workercapacity_test.go rename to cmd/atelet/ateomsupport_test.go index af34b2f5dd..8b220640e1 100644 --- a/cmd/atelet/workercapacity_test.go +++ b/cmd/atelet/ateomsupport_test.go @@ -16,20 +16,75 @@ package main import ( "context" + "crypto/ed25519" + "crypto/rand" + "crypto/tls" + "crypto/x509" "errors" + "math/big" "testing" + "time" + "github.com/agent-substrate/substrate/internal/proto/ateletpb" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/internal/substratex509" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" "github.com/google/go-cmp/cmp" "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/peer" "google.golang.org/grpc/status" "google.golang.org/protobuf/testing/protocmp" - - "github.com/agent-substrate/substrate/internal/proto/ateletpb" - "github.com/agent-substrate/substrate/internal/resources" - "github.com/agent-substrate/substrate/pkg/proto/ateapipb" ) +func workerContext(t *testing.T, podUID string) context.Context { + t.Helper() + cert := workerCertificate(t, podUID, "node") + return peer.NewContext(context.Background(), &peer.Peer{AuthInfo: credentials.TLSInfo{State: tls.ConnectionState{PeerCertificates: []*x509.Certificate{cert}}}}) +} + +func TestVerifyClientOnSameNode(t *testing.T) { + state := tls.ConnectionState{PeerCertificates: []*x509.Certificate{workerCertificate(t, "worker-uid", "node-a")}} + nodeA := &substratex509.PodIdentity{NodeName: "node-a", NodeUID: "node-uid"} + if err := verifyClientOnSameNode(nodeA)(state); err != nil { + t.Fatalf("same-node worker rejected: %v", err) + } + if err := verifyClientOnSameNode(&substratex509.PodIdentity{NodeName: "node-b", NodeUID: "node-uid"})(state); err == nil { + t.Fatal("cross-node worker accepted") + } + if err := verifyClientOnSameNode(&substratex509.PodIdentity{NodeName: "node-a", NodeUID: "replacement-node"})(state); err == nil { + t.Fatal("replacement node accepted") + } +} + +func workerCertificate(t *testing.T, podUID, nodeName string) *x509.Certificate { + t.Helper() + _, key, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + template := &x509.Certificate{SerialNumber: big.NewInt(1), NotBefore: time.Now().Add(-time.Minute), NotAfter: time.Now().Add(time.Hour)} + if err := substratex509.AddPodIdentityToCertificate(&substratex509.PodIdentity{ + Namespace: "workers", ServiceAccountName: "default", ServiceAccountUID: "sa-uid", + PodName: "worker", PodUID: podUID, NodeName: nodeName, NodeUID: "node-uid", + }, template); err != nil { + t.Fatal(err) + } + der, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) + if err != nil { + t.Fatal(err) + } + cert, err := x509.ParseCertificate(der) + if err != nil { + t.Fatal(err) + } + return cert +} + +// TODO: Use bufconn + an actual server implementation. +// +// https://google.github.io/styleguide/go/best-practices.html#use-real-transports type fakeWorkerService struct { ateapipb.WorkerServiceClient @@ -47,7 +102,7 @@ func (s *fakeWorkerService) SetWorkerCapacity(_ context.Context, in *ateapipb.Se func TestSetWorkerCapacityRecordsWhatTheWorkerSays(t *testing.T) { workers := &fakeWorkerService{} - svc := &workerCapacityService{workers: workers} + svc := &ateomSupportServer{workers: workers} ctx := workerContext(t, "pod-a") reported := &ateapipb.WorkerResources{ @@ -73,7 +128,7 @@ func TestSetWorkerCapacityRecordsWhatTheWorkerSays(t *testing.T) { func TestSetWorkerCapacityOmitsUndeterminedCompute(t *testing.T) { workers := &fakeWorkerService{} - svc := &workerCapacityService{workers: workers} + svc := &ateomSupportServer{workers: workers} ctx := workerContext(t, "pod-a") if _, err := svc.SetWorkerCapacity(ctx, &ateletpb.SetWorkerCapacityRequest{Capacity: &ateapipb.WorkerResources{Actors: 1}}); err != nil { @@ -87,7 +142,7 @@ func TestSetWorkerCapacityOmitsUndeterminedCompute(t *testing.T) { func TestSetWorkerCapacityRequiresACertificate(t *testing.T) { workers := &fakeWorkerService{} - svc := &workerCapacityService{workers: workers} + svc := &ateomSupportServer{workers: workers} // No peer identity: a worker may report only what its certificate proves // it is, so there is nothing to attribute this to. @@ -105,7 +160,7 @@ func TestSetWorkerCapacitySurfacesRejection(t *testing.T) { // it retries: it reports once, so a swallowed failure leaves the Worker // with no capacity forever. workers := &fakeWorkerService{err: errors.New("no such worker")} - svc := &workerCapacityService{workers: workers} + svc := &ateomSupportServer{workers: workers} ctx := workerContext(t, "pod-a") if _, err := svc.SetWorkerCapacity(ctx, &ateletpb.SetWorkerCapacityRequest{Capacity: &ateapipb.WorkerResources{Actors: 1}}); err == nil { diff --git a/cmd/atelet/credentialbroker_test.go b/cmd/atelet/credentialbroker_test.go deleted file mode 100644 index fe73545a2f..0000000000 --- a/cmd/atelet/credentialbroker_test.go +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2026 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "crypto/ed25519" - "crypto/rand" - "crypto/tls" - "crypto/x509" - "math/big" - "testing" - "time" - - "github.com/agent-substrate/substrate/internal/substratex509" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/peer" -) - -func workerContext(t *testing.T, podUID string) context.Context { - t.Helper() - cert := workerCertificate(t, podUID, "node") - return peer.NewContext(context.Background(), &peer.Peer{AuthInfo: credentials.TLSInfo{State: tls.ConnectionState{PeerCertificates: []*x509.Certificate{cert}}}}) -} - -func TestVerifyClientOnSameNode(t *testing.T) { - state := tls.ConnectionState{PeerCertificates: []*x509.Certificate{workerCertificate(t, "worker-uid", "node-a")}} - nodeA := &substratex509.PodIdentity{NodeName: "node-a", NodeUID: "node-uid"} - if err := verifyClientOnSameNode(nodeA)(state); err != nil { - t.Fatalf("same-node worker rejected: %v", err) - } - if err := verifyClientOnSameNode(&substratex509.PodIdentity{NodeName: "node-b", NodeUID: "node-uid"})(state); err == nil { - t.Fatal("cross-node worker accepted") - } - if err := verifyClientOnSameNode(&substratex509.PodIdentity{NodeName: "node-a", NodeUID: "replacement-node"})(state); err == nil { - t.Fatal("replacement node accepted") - } -} - -func workerCertificate(t *testing.T, podUID, nodeName string) *x509.Certificate { - t.Helper() - _, key, err := ed25519.GenerateKey(rand.Reader) - if err != nil { - t.Fatal(err) - } - template := &x509.Certificate{SerialNumber: big.NewInt(1), NotBefore: time.Now().Add(-time.Minute), NotAfter: time.Now().Add(time.Hour)} - if err := substratex509.AddPodIdentityToCertificate(&substratex509.PodIdentity{ - Namespace: "workers", ServiceAccountName: "default", ServiceAccountUID: "sa-uid", - PodName: "worker", PodUID: podUID, NodeName: nodeName, NodeUID: "node-uid", - }, template); err != nil { - t.Fatal(err) - } - der, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) - if err != nil { - t.Fatal(err) - } - cert, err := x509.ParseCertificate(der) - if err != nil { - t.Fatal(err) - } - return cert -} diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index 904c207d5a..93dd6f4272 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -351,28 +351,29 @@ func main() { if ateletIdentity == nil { serverboot.Fatal(ctx, "Failed to load atelet Pod identity", fmt.Errorf("credential bundle has no Pod identity")) } - brokerTLS := tlsCfg.Clone() - brokerTLS.VerifyConnection = verifyClientOnSameNode(ateletIdentity) - if err := os.Remove(ateompath.CredentialBrokerSocket); err != nil && !errors.Is(err, os.ErrNotExist) { + + ateomFacingTLS := tlsCfg.Clone() + ateomFacingTLS.VerifyConnection = verifyClientOnSameNode(ateletIdentity) + if err := os.Remove(ateompath.AteomSupportSocket); err != nil && !errors.Is(err, os.ErrNotExist) { serverboot.Fatal(ctx, "Failed to remove stale credential broker socket", err) } - brokerLis, err := net.Listen("unix", ateompath.CredentialBrokerSocket) + ateomFacingLis, err := net.Listen("unix", ateompath.AteomSupportSocket) if err != nil { serverboot.Fatal(ctx, "Failed to listen for credential broker", err) } - defer brokerLis.Close() - if err := os.Chmod(ateompath.CredentialBrokerSocket, 0o600); err != nil { + defer ateomFacingLis.Close() + if err := os.Chmod(ateompath.AteomSupportSocket, 0o600); err != nil { serverboot.Fatal(ctx, "Failed to restrict credential broker socket", err) } - brokerServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(brokerTLS))) - ateletpb.RegisterCredentialBrokerServer(brokerServer, &credentialBroker{ + + ateomFacingSrv := grpc.NewServer(grpc.Creds(credentials.NewTLS(ateomFacingTLS))) + + ateletpb.RegisterAteomSupportServer(ateomFacingSrv, &ateomSupportServer{ controlClient: ateapipb.NewControlClient(ateapiConn), - }) - ateletpb.RegisterWorkerCapacityServer(brokerServer, &workerCapacityService{ - workers: ateapipb.NewWorkerServiceClient(ateapiConn), + workers: ateapipb.NewWorkerServiceClient(ateapiConn), }) go func() { - if err := brokerServer.Serve(brokerLis); err != nil { + if err := ateomFacingSrv.Serve(ateomFacingLis); err != nil { serverboot.Fatal(ctx, "Failed to serve credential broker", err) } }() diff --git a/cmd/atelet/workercapacity.go b/cmd/atelet/workercapacity.go deleted file mode 100644 index b53a102133..0000000000 --- a/cmd/atelet/workercapacity.go +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2026 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "context" - "log/slog" - - "github.com/agent-substrate/substrate/internal/proto/ateletpb" - "github.com/agent-substrate/substrate/pkg/proto/ateapipb" -) - -// workerCapacityService forwards a worker's own account of what it can supply -// to the control plane. The worker is the only thing that knows: the control -// plane sees a Pod, not what the runtime will actually give an actor. -type workerCapacityService struct { - ateletpb.UnimplementedWorkerCapacityServer - - workers ateapipb.WorkerServiceClient -} - -// SetWorkerCapacity records what the calling worker says it has. -// -// It returns the control plane's error unwrapped so the caller retries: a -// worker reports once, so an accepted call is the only thing that puts -// capacity on the Worker, and a Worker record the syncer has not created yet -// is the ordinary reason for a first attempt to fail. -func (s *workerCapacityService) SetWorkerCapacity(ctx context.Context, req *ateletpb.SetWorkerCapacityRequest) (*ateletpb.SetWorkerCapacityResponse, error) { - // Identity comes only from the mTLS certificate, never from the request: - // a worker can report its own capacity and no one else's. - workerIdentity, err := authenticatedWorkerIdentity(ctx) - if err != nil { - return nil, err - } - // Forwarded as reported: the worker speaks the vocabulary the control plane - // records, so there is nothing to translate. - if _, err := s.workers.SetWorkerCapacity(ctx, &ateapipb.SetWorkerCapacityRequest{ - // Workers are global-scoped and named by their pod UID. - Worker: &ateapipb.ObjectRef{Name: workerIdentity.PodUID}, - Capacity: req.GetCapacity(), - }); err != nil { - return nil, err - } - slog.InfoContext(ctx, "Recorded worker capacity", - slog.String("pod_uid", workerIdentity.PodUID), slog.Any("capacity", req.GetCapacity())) - return &ateletpb.SetWorkerCapacityResponse{}, nil -} diff --git a/cmd/ateom-gvisor/main.go b/cmd/ateom-gvisor/main.go index 9dde4d73bb..092005b556 100644 --- a/cmd/ateom-gvisor/main.go +++ b/cmd/ateom-gvisor/main.go @@ -247,7 +247,7 @@ func do(ctx context.Context) error { // that reaches here is a misconfiguration no restart-in-place will fix. go func() { err := ateomcapacity.Report(ctx, ateomcapacity.ReportConfig{ - SocketPath: ateompath.CredentialBrokerSocket, + SocketPath: ateompath.AteomSupportSocket, CredentialBundlePath: *workerCredentialBundle, TrustBundlePath: *podIdentityTrustBundle, }) @@ -1081,7 +1081,7 @@ func (s *AteomService) prepareActorEgress(ctx context.Context, actorAtespace, ac return nil, fmt.Errorf("invalid egress gateway address %q: %w", gateway.GetAddress(), err) } certificateSource, err := atunnel.NewBrokerCertificateSource(atunnel.BrokerConfig{ - SocketPath: ateompath.CredentialBrokerSocket, + SocketPath: ateompath.AteomSupportSocket, CredentialBundlePath: s.workerCredentialBundlePath, TrustBundlePath: s.podIdentityTrustBundlePath, ActorAtespace: actorAtespace, diff --git a/cmd/ateom-microvm/main.go b/cmd/ateom-microvm/main.go index aec16a5cff..ba76a18924 100644 --- a/cmd/ateom-microvm/main.go +++ b/cmd/ateom-microvm/main.go @@ -294,7 +294,7 @@ func do(ctx context.Context) error { // that reaches here is a misconfiguration no restart-in-place will fix. go func() { err := ateomcapacity.Report(ctx, ateomcapacity.ReportConfig{ - SocketPath: ateompath.CredentialBrokerSocket, + SocketPath: ateompath.AteomSupportSocket, CredentialBundlePath: *workerCredentialBundle, TrustBundlePath: *podIdentityTrustBundle, }) @@ -533,7 +533,7 @@ func (s *AteomService) prepareActorEgress(ctx context.Context, actorAtespace, ac return nil, fmt.Errorf("invalid egress gateway address %q: %w", gateway.GetAddress(), err) } certificateSource, err := atunnel.NewBrokerCertificateSource(atunnel.BrokerConfig{ - SocketPath: ateompath.CredentialBrokerSocket, + SocketPath: ateompath.AteomSupportSocket, CredentialBundlePath: s.workerCredentialBundlePath, TrustBundlePath: s.podIdentityTrustBundlePath, diff --git a/internal/ateomcapacity/ateomcapacity.go b/internal/ateomcapacity/ateomcapacity.go index 731304d053..bfd05ae90f 100644 --- a/internal/ateomcapacity/ateomcapacity.go +++ b/internal/ateomcapacity/ateomcapacity.go @@ -151,6 +151,6 @@ func reportOnce(ctx context.Context, socketPath string, tlsConfig *tls.Config, c defer conn.Close() callCtx, cancel := context.WithTimeout(ctx, reportTimeout) defer cancel() - _, err = ateletpb.NewWorkerCapacityClient(conn).SetWorkerCapacity(callCtx, capacity) + _, err = ateletpb.NewAteomSupportClient(conn).SetWorkerCapacity(callCtx, capacity) return err } diff --git a/internal/ateompath/ateompath.go b/internal/ateompath/ateompath.go index 401dd313b6..2a18303c12 100644 --- a/internal/ateompath/ateompath.go +++ b/internal/ateompath/ateompath.go @@ -40,9 +40,9 @@ var ( // under it. ActorsDir = filepath.Join(BasePath, "actors") - // CredentialBrokerSocket is the node-local atelet socket used by atunnel + // AteomSupportSocket is the node-local atelet socket used by atunnel // to request credentials for the worker's current actor assignment. - CredentialBrokerSocket = filepath.Join(BasePath, "credential-broker.sock") + AteomSupportSocket = filepath.Join(BasePath, "ateom-support.sock") ) func RunSCBinaryPath(sha256 string) string { diff --git a/internal/atunnel/credential.go b/internal/atunnel/credential.go index 83cde97eae..4986ed6b9f 100644 --- a/internal/atunnel/credential.go +++ b/internal/atunnel/credential.go @@ -112,7 +112,7 @@ func (s *BrokerCertificateSource) MintAteomCertificate(ctx context.Context) (tim return time.Time{}, err } defer conn.Close() - resp, err := ateletpb.NewCredentialBrokerClient(conn).MintActorCertificate(ctx, &ateletpb.MintActorCertificateRequest{ + resp, err := ateletpb.NewAteomSupportClient(conn).MintActorCertificate(ctx, &ateletpb.MintActorCertificateRequest{ ActorAtespace: s.actorAtespace, ActorName: s.actorName, ActorUid: s.actorUID, diff --git a/internal/atunnel/credential_test.go b/internal/atunnel/credential_test.go index c6c45bbf70..8b58a68b38 100644 --- a/internal/atunnel/credential_test.go +++ b/internal/atunnel/credential_test.go @@ -93,15 +93,15 @@ func TestBrokerCertificateSourceRejectsUnexpectedActor(t *testing.T) { } } -type credentialBrokerStub struct { - ateletpb.UnimplementedCredentialBrokerServer +type ateomSupportStub struct { + ateletpb.UnimplementedAteomSupportServer ca *testCA lifetime time.Duration publicKeys chan []byte actorUID string } -func (s *credentialBrokerStub) MintActorCertificate(_ context.Context, req *ateletpb.MintActorCertificateRequest) (*ateletpb.MintActorCertificateResponse, error) { +func (s *ateomSupportStub) MintActorCertificate(_ context.Context, req *ateletpb.MintActorCertificateRequest) (*ateletpb.MintActorCertificateResponse, error) { if req.GetActorUid() != "actor-uid" { return nil, status.Error(codes.FailedPrecondition, "unexpected actor UID") } @@ -129,7 +129,7 @@ func (s *credentialBrokerStub) MintActorCertificate(_ context.Context, req *atel return &ateletpb.MintActorCertificateResponse{ActorCertificates: [][]byte{der}}, nil } -func newTestBrokerCertificateSource(t *testing.T, ateletIdentity *substratex509.PodIdentity, lifetime time.Duration) (*BrokerCertificateSource, *credentialBrokerStub) { +func newTestBrokerCertificateSource(t *testing.T, ateletIdentity *substratex509.PodIdentity, lifetime time.Duration) (*BrokerCertificateSource, *ateomSupportStub) { t.Helper() ca := newTestCA(t) workerCert := issueTestPodCertificate(t, ca, &substratex509.PodIdentity{ @@ -172,8 +172,8 @@ func newTestBrokerCertificateSource(t *testing.T, ateletIdentity *substratex509. ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: clientCAs, }))) - broker := &credentialBrokerStub{ca: ca, lifetime: lifetime, publicKeys: make(chan []byte, 2), actorUID: "actor-uid"} - ateletpb.RegisterCredentialBrokerServer(server, broker) + broker := &ateomSupportStub{ca: ca, lifetime: lifetime, publicKeys: make(chan []byte, 2), actorUID: "actor-uid"} + ateletpb.RegisterAteomSupportServer(server, broker) go func() { _ = server.Serve(listener) }() t.Cleanup(func() { server.Stop() diff --git a/internal/proto/ateletpb/atelet.pb.go b/internal/proto/ateletpb/atelet.pb.go index 9a82d70afa..4c4047ae8c 100644 --- a/internal/proto/ateletpb/atelet.pb.go +++ b/internal/proto/ateletpb/atelet.pb.go @@ -2873,10 +2873,9 @@ const file_atelet_proto_rawDesc = "" + "\x1aSNAPSHOT_SCOPE_UNSPECIFIED\x10\x00\x12\x17\n" + "\x13SNAPSHOT_SCOPE_FULL\x10\x01\x12\x17\n" + "\x13SNAPSHOT_SCOPE_DATA\x10\x02\x12!\n" + - "\x1dSNAPSHOT_SCOPE_DATA_ON_GOLDEN\x10\x032w\n" + - "\x10CredentialBroker\x12c\n" + - "\x14MintActorCertificate\x12#.atelet.MintActorCertificateRequest\x1a$.atelet.MintActorCertificateResponse\"\x002l\n" + - "\x0eWorkerCapacity\x12Z\n" + + "\x1dSNAPSHOT_SCOPE_DATA_ON_GOLDEN\x10\x032\xcf\x01\n" + + "\fAteomSupport\x12c\n" + + "\x14MintActorCertificate\x12#.atelet.MintActorCertificateRequest\x1a$.atelet.MintActorCertificateResponse\"\x00\x12Z\n" + "\x11SetWorkerCapacity\x12 .atelet.SetWorkerCapacityRequest\x1a!.atelet.SetWorkerCapacityResponse\"\x002\xf3\x02\n" + "\vAteomHerder\x120\n" + "\x03Run\x12\x12.atelet.RunRequest\x1a\x13.atelet.RunResponse\"\x00\x12E\n" + @@ -2988,15 +2987,15 @@ var file_atelet_proto_depIdxs = []int32{ 10, // 37: atelet.RestoreRequest.egress_gateway:type_name -> atelet.EgressGateway 11, // 38: atelet.ArchAssets.FilesEntry.value:type_name -> atelet.AssetFile 12, // 39: atelet.SandboxAssets.AssetsEntry.value:type_name -> atelet.ArchAssets - 5, // 40: atelet.CredentialBroker.MintActorCertificate:input_type -> atelet.MintActorCertificateRequest - 3, // 41: atelet.WorkerCapacity.SetWorkerCapacity:input_type -> atelet.SetWorkerCapacityRequest + 5, // 40: atelet.AteomSupport.MintActorCertificate:input_type -> atelet.MintActorCertificateRequest + 3, // 41: atelet.AteomSupport.SetWorkerCapacity:input_type -> atelet.SetWorkerCapacityRequest 9, // 42: atelet.AteomHerder.Run:input_type -> atelet.RunRequest 35, // 43: atelet.AteomHerder.Checkpoint:input_type -> atelet.CheckpointRequest 39, // 44: atelet.AteomHerder.Restore:input_type -> atelet.RestoreRequest 37, // 45: atelet.AteomHerder.UploadPausedCheckpoint:input_type -> atelet.UploadPausedCheckpointRequest 7, // 46: atelet.AteomHerder.Terminate:input_type -> atelet.TerminateRequest - 6, // 47: atelet.CredentialBroker.MintActorCertificate:output_type -> atelet.MintActorCertificateResponse - 4, // 48: atelet.WorkerCapacity.SetWorkerCapacity:output_type -> atelet.SetWorkerCapacityResponse + 6, // 47: atelet.AteomSupport.MintActorCertificate:output_type -> atelet.MintActorCertificateResponse + 4, // 48: atelet.AteomSupport.SetWorkerCapacity:output_type -> atelet.SetWorkerCapacityResponse 32, // 49: atelet.AteomHerder.Run:output_type -> atelet.RunResponse 36, // 50: atelet.AteomHerder.Checkpoint:output_type -> atelet.CheckpointResponse 40, // 51: atelet.AteomHerder.Restore:output_type -> atelet.RestoreResponse @@ -3041,7 +3040,7 @@ func file_atelet_proto_init() { NumEnums: 3, NumMessages: 41, NumExtensions: 0, - NumServices: 3, + NumServices: 2, }, GoTypes: file_atelet_proto_goTypes, DependencyIndexes: file_atelet_proto_depIdxs, diff --git a/internal/proto/ateletpb/atelet.proto b/internal/proto/ateletpb/atelet.proto index f75b66a03d..c4c79201dc 100644 --- a/internal/proto/ateletpb/atelet.proto +++ b/internal/proto/ateletpb/atelet.proto @@ -20,23 +20,19 @@ option go_package = "github.com/agent-substrate/substrate/internal/proto/ateletp import "pkg/proto/ateapipb/ateapi.proto"; -// CredentialBroker provides on-demand services to ateom. +// AteomSupport provides callouts for ateom. // -// TODO(identity): Rename to something more generic like AteomSupportService. -service CredentialBroker { +// Called by individual ateom pods over a local connection, authenticated with +// ateom's k8s pod identity mTLS certificate. +service AteomSupport { // Request an atunnel certificate for the given actor. // // TODO(identity): Rename to MintAtunnelCertificate, as distinct from // MintActorCertificate (which would be used for certificates projected into // the actor filesystem, when/if we support those). rpc MintActorCertificate(MintActorCertificateRequest) returns (MintActorCertificateResponse) {} -} -// WorkerCapacity is how a worker tells the node-local atelet what it can -// supply to the actors it hosts, for atelet to forward to the control plane's -// WorkerService.SetWorkerCapacity, which this mirrors. The worker is identified -// by its mTLS certificate, never by the request. -service WorkerCapacity { + // Report capacity and supply for this worker back to atelet. rpc SetWorkerCapacity(SetWorkerCapacityRequest) returns (SetWorkerCapacityResponse) {} } @@ -68,6 +64,10 @@ message MintActorCertificateResponse { repeated bytes actor_certificates = 1; } +// AteomHerder allows ate-apiserver to issue control calls to the atelet. +// +// Called by ate-api-server over cluster networking. ate-api-server +// authenticates with its k8s pod identity mTLS certificate. service AteomHerder { // Run tells atelet to create a new containerized workload from scratch on an // ateom. diff --git a/internal/proto/ateletpb/atelet_grpc.pb.go b/internal/proto/ateletpb/atelet_grpc.pb.go index e637c3daf6..1a51254c6c 100644 --- a/internal/proto/ateletpb/atelet_grpc.pb.go +++ b/internal/proto/ateletpb/atelet_grpc.pb.go @@ -33,231 +33,161 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - CredentialBroker_MintActorCertificate_FullMethodName = "/atelet.CredentialBroker/MintActorCertificate" + AteomSupport_MintActorCertificate_FullMethodName = "/atelet.AteomSupport/MintActorCertificate" + AteomSupport_SetWorkerCapacity_FullMethodName = "/atelet.AteomSupport/SetWorkerCapacity" ) -// CredentialBrokerClient is the client API for CredentialBroker service. +// AteomSupportClient is the client API for AteomSupport service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. // -// CredentialBroker provides on-demand services to ateom. +// AteomSupport provides callouts for ateom. // -// TODO(identity): Rename to something more generic like AteomSupportService. -type CredentialBrokerClient interface { +// Called by individual ateom pods over a local connection, authenticated with +// ateom's k8s pod identity mTLS certificate. +type AteomSupportClient interface { // Request an atunnel certificate for the given actor. // // TODO(identity): Rename to MintAtunnelCertificate, as distinct from // MintActorCertificate (which would be used for certificates projected into // the actor filesystem, when/if we support those). MintActorCertificate(ctx context.Context, in *MintActorCertificateRequest, opts ...grpc.CallOption) (*MintActorCertificateResponse, error) + // Report capacity and supply for this worker back to atelet. + SetWorkerCapacity(ctx context.Context, in *SetWorkerCapacityRequest, opts ...grpc.CallOption) (*SetWorkerCapacityResponse, error) } -type credentialBrokerClient struct { +type ateomSupportClient struct { cc grpc.ClientConnInterface } -func NewCredentialBrokerClient(cc grpc.ClientConnInterface) CredentialBrokerClient { - return &credentialBrokerClient{cc} +func NewAteomSupportClient(cc grpc.ClientConnInterface) AteomSupportClient { + return &ateomSupportClient{cc} } -func (c *credentialBrokerClient) MintActorCertificate(ctx context.Context, in *MintActorCertificateRequest, opts ...grpc.CallOption) (*MintActorCertificateResponse, error) { +func (c *ateomSupportClient) MintActorCertificate(ctx context.Context, in *MintActorCertificateRequest, opts ...grpc.CallOption) (*MintActorCertificateResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(MintActorCertificateResponse) - err := c.cc.Invoke(ctx, CredentialBroker_MintActorCertificate_FullMethodName, in, out, cOpts...) + err := c.cc.Invoke(ctx, AteomSupport_MintActorCertificate_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *ateomSupportClient) SetWorkerCapacity(ctx context.Context, in *SetWorkerCapacityRequest, opts ...grpc.CallOption) (*SetWorkerCapacityResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SetWorkerCapacityResponse) + err := c.cc.Invoke(ctx, AteomSupport_SetWorkerCapacity_FullMethodName, in, out, cOpts...) if err != nil { return nil, err } return out, nil } -// CredentialBrokerServer is the server API for CredentialBroker service. -// All implementations must embed UnimplementedCredentialBrokerServer +// AteomSupportServer is the server API for AteomSupport service. +// All implementations must embed UnimplementedAteomSupportServer // for forward compatibility. // -// CredentialBroker provides on-demand services to ateom. +// AteomSupport provides callouts for ateom. // -// TODO(identity): Rename to something more generic like AteomSupportService. -type CredentialBrokerServer interface { +// Called by individual ateom pods over a local connection, authenticated with +// ateom's k8s pod identity mTLS certificate. +type AteomSupportServer interface { // Request an atunnel certificate for the given actor. // // TODO(identity): Rename to MintAtunnelCertificate, as distinct from // MintActorCertificate (which would be used for certificates projected into // the actor filesystem, when/if we support those). MintActorCertificate(context.Context, *MintActorCertificateRequest) (*MintActorCertificateResponse, error) - mustEmbedUnimplementedCredentialBrokerServer() + // Report capacity and supply for this worker back to atelet. + SetWorkerCapacity(context.Context, *SetWorkerCapacityRequest) (*SetWorkerCapacityResponse, error) + mustEmbedUnimplementedAteomSupportServer() } -// UnimplementedCredentialBrokerServer must be embedded to have +// UnimplementedAteomSupportServer must be embedded to have // forward compatible implementations. // // NOTE: this should be embedded by value instead of pointer to avoid a nil // pointer dereference when methods are called. -type UnimplementedCredentialBrokerServer struct{} +type UnimplementedAteomSupportServer struct{} -func (UnimplementedCredentialBrokerServer) MintActorCertificate(context.Context, *MintActorCertificateRequest) (*MintActorCertificateResponse, error) { +func (UnimplementedAteomSupportServer) MintActorCertificate(context.Context, *MintActorCertificateRequest) (*MintActorCertificateResponse, error) { return nil, status.Error(codes.Unimplemented, "method MintActorCertificate not implemented") } -func (UnimplementedCredentialBrokerServer) mustEmbedUnimplementedCredentialBrokerServer() {} -func (UnimplementedCredentialBrokerServer) testEmbeddedByValue() {} +func (UnimplementedAteomSupportServer) SetWorkerCapacity(context.Context, *SetWorkerCapacityRequest) (*SetWorkerCapacityResponse, error) { + return nil, status.Error(codes.Unimplemented, "method SetWorkerCapacity not implemented") +} +func (UnimplementedAteomSupportServer) mustEmbedUnimplementedAteomSupportServer() {} +func (UnimplementedAteomSupportServer) testEmbeddedByValue() {} -// UnsafeCredentialBrokerServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to CredentialBrokerServer will +// UnsafeAteomSupportServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AteomSupportServer will // result in compilation errors. -type UnsafeCredentialBrokerServer interface { - mustEmbedUnimplementedCredentialBrokerServer() +type UnsafeAteomSupportServer interface { + mustEmbedUnimplementedAteomSupportServer() } -func RegisterCredentialBrokerServer(s grpc.ServiceRegistrar, srv CredentialBrokerServer) { - // If the following call panics, it indicates UnimplementedCredentialBrokerServer was +func RegisterAteomSupportServer(s grpc.ServiceRegistrar, srv AteomSupportServer) { + // If the following call panics, it indicates UnimplementedAteomSupportServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { t.testEmbeddedByValue() } - s.RegisterService(&CredentialBroker_ServiceDesc, srv) + s.RegisterService(&AteomSupport_ServiceDesc, srv) } -func _CredentialBroker_MintActorCertificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _AteomSupport_MintActorCertificate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MintActorCertificateRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(CredentialBrokerServer).MintActorCertificate(ctx, in) + return srv.(AteomSupportServer).MintActorCertificate(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: CredentialBroker_MintActorCertificate_FullMethodName, + FullMethod: AteomSupport_MintActorCertificate_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(CredentialBrokerServer).MintActorCertificate(ctx, req.(*MintActorCertificateRequest)) + return srv.(AteomSupportServer).MintActorCertificate(ctx, req.(*MintActorCertificateRequest)) } return interceptor(ctx, in, info, handler) } -// CredentialBroker_ServiceDesc is the grpc.ServiceDesc for CredentialBroker service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var CredentialBroker_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "atelet.CredentialBroker", - HandlerType: (*CredentialBrokerServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "MintActorCertificate", - Handler: _CredentialBroker_MintActorCertificate_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "atelet.proto", -} - -const ( - WorkerCapacity_SetWorkerCapacity_FullMethodName = "/atelet.WorkerCapacity/SetWorkerCapacity" -) - -// WorkerCapacityClient is the client API for WorkerCapacity service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -// -// WorkerCapacity is how a worker tells the node-local atelet what it can -// supply to the actors it hosts, for atelet to forward to the control plane's -// WorkerService.SetWorkerCapacity, which this mirrors. The worker is identified -// by its mTLS certificate, never by the request. -type WorkerCapacityClient interface { - SetWorkerCapacity(ctx context.Context, in *SetWorkerCapacityRequest, opts ...grpc.CallOption) (*SetWorkerCapacityResponse, error) -} - -type workerCapacityClient struct { - cc grpc.ClientConnInterface -} - -func NewWorkerCapacityClient(cc grpc.ClientConnInterface) WorkerCapacityClient { - return &workerCapacityClient{cc} -} - -func (c *workerCapacityClient) SetWorkerCapacity(ctx context.Context, in *SetWorkerCapacityRequest, opts ...grpc.CallOption) (*SetWorkerCapacityResponse, error) { - cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(SetWorkerCapacityResponse) - err := c.cc.Invoke(ctx, WorkerCapacity_SetWorkerCapacity_FullMethodName, in, out, cOpts...) - if err != nil { - return nil, err - } - return out, nil -} - -// WorkerCapacityServer is the server API for WorkerCapacity service. -// All implementations must embed UnimplementedWorkerCapacityServer -// for forward compatibility. -// -// WorkerCapacity is how a worker tells the node-local atelet what it can -// supply to the actors it hosts, for atelet to forward to the control plane's -// WorkerService.SetWorkerCapacity, which this mirrors. The worker is identified -// by its mTLS certificate, never by the request. -type WorkerCapacityServer interface { - SetWorkerCapacity(context.Context, *SetWorkerCapacityRequest) (*SetWorkerCapacityResponse, error) - mustEmbedUnimplementedWorkerCapacityServer() -} - -// UnimplementedWorkerCapacityServer must be embedded to have -// forward compatible implementations. -// -// NOTE: this should be embedded by value instead of pointer to avoid a nil -// pointer dereference when methods are called. -type UnimplementedWorkerCapacityServer struct{} - -func (UnimplementedWorkerCapacityServer) SetWorkerCapacity(context.Context, *SetWorkerCapacityRequest) (*SetWorkerCapacityResponse, error) { - return nil, status.Error(codes.Unimplemented, "method SetWorkerCapacity not implemented") -} -func (UnimplementedWorkerCapacityServer) mustEmbedUnimplementedWorkerCapacityServer() {} -func (UnimplementedWorkerCapacityServer) testEmbeddedByValue() {} - -// UnsafeWorkerCapacityServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to WorkerCapacityServer will -// result in compilation errors. -type UnsafeWorkerCapacityServer interface { - mustEmbedUnimplementedWorkerCapacityServer() -} - -func RegisterWorkerCapacityServer(s grpc.ServiceRegistrar, srv WorkerCapacityServer) { - // If the following call panics, it indicates UnimplementedWorkerCapacityServer was - // embedded by pointer and is nil. This will cause panics if an - // unimplemented method is ever invoked, so we test this at initialization - // time to prevent it from happening at runtime later due to I/O. - if t, ok := srv.(interface{ testEmbeddedByValue() }); ok { - t.testEmbeddedByValue() - } - s.RegisterService(&WorkerCapacity_ServiceDesc, srv) -} - -func _WorkerCapacity_SetWorkerCapacity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _AteomSupport_SetWorkerCapacity_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(SetWorkerCapacityRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(WorkerCapacityServer).SetWorkerCapacity(ctx, in) + return srv.(AteomSupportServer).SetWorkerCapacity(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: WorkerCapacity_SetWorkerCapacity_FullMethodName, + FullMethod: AteomSupport_SetWorkerCapacity_FullMethodName, } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(WorkerCapacityServer).SetWorkerCapacity(ctx, req.(*SetWorkerCapacityRequest)) + return srv.(AteomSupportServer).SetWorkerCapacity(ctx, req.(*SetWorkerCapacityRequest)) } return interceptor(ctx, in, info, handler) } -// WorkerCapacity_ServiceDesc is the grpc.ServiceDesc for WorkerCapacity service. +// AteomSupport_ServiceDesc is the grpc.ServiceDesc for AteomSupport service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) -var WorkerCapacity_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "atelet.WorkerCapacity", - HandlerType: (*WorkerCapacityServer)(nil), +var AteomSupport_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "atelet.AteomSupport", + HandlerType: (*AteomSupportServer)(nil), Methods: []grpc.MethodDesc{ + { + MethodName: "MintActorCertificate", + Handler: _AteomSupport_MintActorCertificate_Handler, + }, { MethodName: "SetWorkerCapacity", - Handler: _WorkerCapacity_SetWorkerCapacity_Handler, + Handler: _AteomSupport_SetWorkerCapacity_Handler, }, }, Streams: []grpc.StreamDesc{}, @@ -275,6 +205,11 @@ const ( // AteomHerderClient is the client API for AteomHerder service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +// +// AteomHerder allows ate-apiserver to issue control calls to the atelet. +// +// Called by ate-api-server over cluster networking. ate-api-server +// authenticates with its k8s pod identity mTLS certificate. type AteomHerderClient interface { // Run tells atelet to create a new containerized workload from scratch on an // ateom. @@ -356,6 +291,11 @@ func (c *ateomHerderClient) Terminate(ctx context.Context, in *TerminateRequest, // AteomHerderServer is the server API for AteomHerder service. // All implementations must embed UnimplementedAteomHerderServer // for forward compatibility. +// +// AteomHerder allows ate-apiserver to issue control calls to the atelet. +// +// Called by ate-api-server over cluster networking. ate-api-server +// authenticates with its k8s pod identity mTLS certificate. type AteomHerderServer interface { // Run tells atelet to create a new containerized workload from scratch on an // ateom.