diff --git a/CHANGELOG.yml b/CHANGELOG.yml index dff8323209..601629c237 100644 --- a/CHANGELOG.yml +++ b/CHANGELOG.yml @@ -24,6 +24,18 @@ # # For older changes, see CHANGELOG.OLD.md items: + - version: 2.27.0 + date: (TBD) + notes: + - type: feature + title: Port Information in List Output + body: >- + The `telepresence list` command now includes comprehensive port information for each workload in multiple output formats. + This enhancement allows developers to see which ports are available on interceptable workloads without needing to use `kubectl`. + The port information includes both container ports (always present) and service ports (when available), along with protocol (TCP/UDP) + and optional port names. This correctly handles headless services (container ports only) and replacement intercepts (which target + container ports). This is particularly useful for VS Code extensions and other tools that need to display port information to users. + docs: reference/client/list - version: 2.26.0 date: (TBD) notes: diff --git a/cmd/traffic/cmd/manager/state/workload_info_watcher.go b/cmd/traffic/cmd/manager/state/workload_info_watcher.go index d5469ba2e8..06e85ae422 100644 --- a/cmd/traffic/cmd/manager/state/workload_info_watcher.go +++ b/cmd/traffic/cmd/manager/state/workload_info_watcher.go @@ -8,14 +8,17 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/timestamppb" "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" + k8stypes "k8s.io/apimachinery/pkg/types" "github.com/datawire/dlib/dlog" rpc "github.com/telepresenceio/telepresence/rpc/v2/manager" + "github.com/telepresenceio/telepresence/v2/cmd/traffic/cmd/manager/managerutil" "github.com/telepresenceio/telepresence/v2/cmd/traffic/cmd/manager/mutator" + "github.com/telepresenceio/telepresence/v2/pkg/agentconfig" "github.com/telepresenceio/telepresence/v2/pkg/agentmap" "github.com/telepresenceio/telepresence/v2/pkg/k8sapi" "github.com/telepresenceio/telepresence/v2/pkg/tunnel" + "github.com/telepresenceio/telepresence/v2/pkg/types" "github.com/telepresenceio/telepresence/v2/pkg/workload" ) @@ -171,7 +174,84 @@ func rpcWorkloadState(s workload.State) (state rpc.WorkloadInfo_State) { return state } -func rpcWorkload(wl k8sapi.Workload, as rpc.WorkloadInfo_AgentState, iClients []*rpc.WorkloadInfo_Intercept) *rpc.WorkloadInfo { +func extractPortsFromSidecar(_ context.Context, sc *agentconfig.Sidecar) []*rpc.WorkloadPortInfo { + if sc == nil { + return nil + } + + var ports []*rpc.WorkloadPortInfo + seenPorts := make(map[types.PortAndProto]bool) // Track seen port+protocol combinations to avoid duplicates + + // Extract ports from all containers in the sidecar + for _, container := range sc.Containers { + for _, intercept := range container.Intercepts { + // Create a unique key using container port number and protocol + // This allows the same port with different protocols (TCP/UDP) + // We use container port because service port may not be present for headless workloads + portKey := types.PortAndProto{ + Port: intercept.ContainerPort, + Proto: intercept.Protocol, + } + + if !seenPorts[portKey] { + seenPorts[portKey] = true + protocol := intercept.Protocol.String() + ports = append(ports, &rpc.WorkloadPortInfo{ + ContainerPortName: intercept.ContainerPortName, + ContainerPort: int32(intercept.ContainerPort), + Protocol: protocol, + ServicePortName: intercept.ServicePortName, + ServicePort: int32(intercept.ServicePort), + }) + } + } + } + + return ports +} + +func extractPortsForWorkload(ctx context.Context, wl k8sapi.Workload) []*rpc.WorkloadPortInfo { + // Check if we already have a sidecar config from an installed traffic-agent + m := mutator.GetMap(ctx) + if m == nil { + dlog.Debugf(ctx, "mutator map not available, cannot discover ports for %s", wl) + return nil + } + + sc := m.Get(wl.GetName(), wl.GetNamespace()) + if sc == nil { + // No existing sidecar, generate a new one to discover ports + // Only attempt generation if an agent image has been configured (i.e., agent injector is enabled) + if ir := managerutil.GetAgentImageRetriever(ctx); ir != nil { + agentImage := ir.GetImage() + + // Generate the sidecar config which properly maps service ports to container ports + gc, err := managerutil.GetEnv(ctx).GeneratorConfig(agentImage) + if err != nil { + dlog.Warnf(ctx, "failed to get generator config for %s: %v", wl, err) + return nil + } + + sc, err = gc.Generate(ctx, wl, nil) + if err != nil { + dlog.Debugf(ctx, "failed to generate sidecar config for %s: %v", wl, err) + return nil + } + } else { + // Agent injector is not enabled, unable to discover ports + dlog.Debugf(ctx, "agent injector not enabled, unable to discover ports for %s", wl) + return nil + } + } + + return extractPortsFromSidecar(ctx, sc) +} + +func (wf *workloadInfoWatcher) rpcWorkload(wl k8sapi.Workload, as rpc.WorkloadInfo_AgentState, iClients []*rpc.WorkloadInfo_Intercept) *rpc.WorkloadInfo { + var ports []*rpc.WorkloadPortInfo + if wf.State != nil && wf.backgroundCtx != nil { + ports = extractPortsForWorkload(wf.backgroundCtx, wl) + } return &rpc.WorkloadInfo{ Kind: workload.RpcKind(wl.GetKind()), Name: wl.GetName(), @@ -180,6 +260,7 @@ func rpcWorkload(wl k8sapi.Workload, as rpc.WorkloadInfo_AgentState, iClients [] State: rpcWorkloadState(workload.GetWorkloadState(wl)), AgentState: as, InterceptClients: iClients, + Ports: ports, } } @@ -191,7 +272,7 @@ func (wf *workloadInfoWatcher) addEvent( ) { wf.workloadEvents[wl.GetName()] = &rpc.WorkloadEvent{ Type: rpc.WorkloadEvent_Type(eventType), - Workload: rpcWorkload(wl, as, iClients), + Workload: wf.rpcWorkload(wl, as, iClients), } wf.resetTicker() } @@ -232,7 +313,7 @@ func (wf *workloadInfoWatcher) handleWorkloadsSnapshot(ctx context.Context, wes if we.Type == EventTypeUpdate { lew, ok := wf.lastEvents[wl.GetName()] if ok && (lew.Type == rpc.WorkloadEvent_ADDED_UNSPECIFIED || lew.Type == rpc.WorkloadEvent_MODIFIED) && - proto.Equal(lew.Workload, rpcWorkload(we.Workload, as, iClients)) { + proto.Equal(lew.Workload, wf.rpcWorkload(we.Workload, as, iClients)) { break } } @@ -248,7 +329,7 @@ func (wf *workloadInfoWatcher) handleAgentSnapshot(ctx context.Context, ais map[ m := mutator.GetMap(ctx) for k, a := range oldAgentInfos { ai, ok := ais[k] - if !ok || m.IsInactive(types.UID(ai.PodUid)) { + if !ok || m.IsInactive(k8stypes.UID(ai.PodUid)) { name := a.Name as := rpc.WorkloadInfo_NO_AGENT_UNSPECIFIED if w, ok := wf.workloadEvents[name]; ok && w.Type != rpc.WorkloadEvent_DELETED { @@ -278,7 +359,7 @@ func (wf *workloadInfoWatcher) handleAgentSnapshot(ctx context.Context, ais map[ } } for _, a := range ais { - if m.IsInactive(types.UID(a.PodUid)) { + if m.IsInactive(k8stypes.UID(a.PodUid)) { continue } name := a.Name diff --git a/cmd/traffic/cmd/manager/state/workload_info_watcher_test.go b/cmd/traffic/cmd/manager/state/workload_info_watcher_test.go new file mode 100644 index 0000000000..efd2cd02f9 --- /dev/null +++ b/cmd/traffic/cmd/manager/state/workload_info_watcher_test.go @@ -0,0 +1,483 @@ +package state + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/datawire/dlib/dlog" + rpc "github.com/telepresenceio/telepresence/rpc/v2/manager" + "github.com/telepresenceio/telepresence/v2/pkg/agentconfig" + "github.com/telepresenceio/telepresence/v2/pkg/types" +) + +// TestExtractPortsFromSidecarNil tests extractPortsFromSidecar with nil sidecar. +func TestExtractPortsFromSidecarNil(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + ports := extractPortsFromSidecar(ctx, nil) + assert.Nil(t, ports) +} + +// TestExtractPortsFromSidecarNoContainers tests extractPortsFromSidecar with empty containers. +func TestExtractPortsFromSidecarNoContainers(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{}, + } + ports := extractPortsFromSidecar(ctx, sc) + assert.Nil(t, ports) +} + +// TestExtractPortsFromSidecarSinglePort tests extractPortsFromSidecar with a single port. +func TestExtractPortsFromSidecarSinglePort(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 8080, + ContainerPortName: "http", + Protocol: types.ProtoTCP, + AgentPort: 8081, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + require.Len(t, ports, 1) + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "http", + ContainerPort: 8080, + Protocol: "TCP", + ServicePortName: "", + ServicePort: 0, + }, ports[0]) +} + +// TestExtractPortsFromSidecarMultiplePorts tests extractPortsFromSidecar with multiple ports. +func TestExtractPortsFromSidecarMultiplePorts(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 8080, + ContainerPortName: "http", + Protocol: types.ProtoTCP, + AgentPort: 8081, + }, + { + ContainerPort: 9090, + ContainerPortName: "metrics", + Protocol: types.ProtoTCP, + AgentPort: 9091, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + require.Len(t, ports, 2) + // Check that both ports are present (order may vary) + portMap := make(map[int32]*rpc.WorkloadPortInfo) + for _, p := range ports { + portMap[p.ContainerPort] = p + } + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "http", + ContainerPort: 8080, + Protocol: "TCP", + ServicePortName: "", + ServicePort: 0, + }, portMap[8080]) + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "metrics", + ContainerPort: 9090, + Protocol: "TCP", + ServicePortName: "", + ServicePort: 0, + }, portMap[9090]) +} + +// TestExtractPortsFromSidecarMultipleContainers tests extractPortsFromSidecar with multiple containers. +func TestExtractPortsFromSidecarMultipleContainers(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 8080, + ContainerPortName: "http", + Protocol: types.ProtoTCP, + AgentPort: 8081, + }, + }, + }, + { + Name: "worker", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 5000, + ContainerPortName: "grpc", + Protocol: types.ProtoTCP, + AgentPort: 5001, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + require.Len(t, ports, 2) + portMap := make(map[int32]*rpc.WorkloadPortInfo) + for _, p := range ports { + portMap[p.ContainerPort] = p + } + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "http", + ContainerPort: 8080, + Protocol: "TCP", + ServicePortName: "", + ServicePort: 0, + }, portMap[8080]) + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "grpc", + ContainerPort: 5000, + Protocol: "TCP", + ServicePortName: "", + ServicePort: 0, + }, portMap[5000]) +} + +// TestExtractPortsFromSidecarDuplicatePortSameProtocol tests that duplicate ports with same protocol are deduplicated. +func TestExtractPortsFromSidecarDuplicatePortSameProtocol(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 8080, + ContainerPortName: "http", + Protocol: types.ProtoTCP, + AgentPort: 8081, + }, + { + // Same port and protocol, should be deduplicated + ContainerPort: 8080, + ContainerPortName: "http", + Protocol: types.ProtoTCP, + AgentPort: 8082, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + // Should only have one port even though there are two intercepts + require.Len(t, ports, 1) + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "http", + ContainerPort: 8080, + Protocol: "TCP", + ServicePortName: "", + ServicePort: 0, + }, ports[0]) +} + +// TestExtractPortsFromSidecarTCPandUDP tests that same port with TCP and UDP are both included. +func TestExtractPortsFromSidecarTCPandUDP(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 5353, + ContainerPortName: "dns", + Protocol: types.ProtoTCP, + AgentPort: 5354, + }, + { + // Same port, different protocol + ContainerPort: 5353, + ContainerPortName: "dns", + Protocol: types.ProtoUDP, + AgentPort: 5355, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + // Should have both TCP and UDP entries + require.Len(t, ports, 2) + protocolMap := make(map[string]*rpc.WorkloadPortInfo) + for _, p := range ports { + protocolMap[p.Protocol] = p + } + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "dns", + ContainerPort: 5353, + Protocol: "TCP", + ServicePortName: "", + ServicePort: 0, + }, protocolMap["TCP"]) + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "dns", + ContainerPort: 5353, + Protocol: "UDP", + ServicePortName: "", + ServicePort: 0, + }, protocolMap["UDP"]) +} + +// TestExtractPortsFromSidecarNoPortName tests port extraction when ContainerPortName is empty. +func TestExtractPortsFromSidecarNoPortName(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 8080, + ContainerPortName: "", // No port name + Protocol: types.ProtoTCP, + AgentPort: 8081, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + require.Len(t, ports, 1) + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "", + ContainerPort: 8080, + Protocol: "TCP", + ServicePortName: "", + ServicePort: 0, + }, ports[0]) +} + +// TestExtractPortsFromSidecarComplexScenario tests a complex scenario with multiple containers, +// multiple ports, duplicate deduplication, and TCP/UDP. +func TestExtractPortsFromSidecarComplexScenario(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 8080, + ContainerPortName: "http", + Protocol: types.ProtoTCP, + AgentPort: 8081, + }, + { + // Duplicate port/protocol + ContainerPort: 8080, + ContainerPortName: "http", + Protocol: types.ProtoTCP, + AgentPort: 8082, + }, + { + // Same port, different protocol + ContainerPort: 8080, + ContainerPortName: "http", + Protocol: types.ProtoUDP, + AgentPort: 8083, + }, + }, + }, + { + Name: "metrics", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 9090, + ContainerPortName: "metrics", + Protocol: types.ProtoTCP, + AgentPort: 9091, + }, + { + ContainerPort: 5353, + ContainerPortName: "dns", + Protocol: types.ProtoTCP, + AgentPort: 5354, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + // Expected: 8080 TCP, 8080 UDP, 9090 TCP, 5353 TCP (4 ports total) + require.Len(t, ports, 4) + + portProtocolMap := make(map[string]int32) + for _, p := range ports { + key := p.ContainerPortName + "_" + p.Protocol + portProtocolMap[key] = p.ContainerPort + } + + assert.Equal(t, int32(8080), portProtocolMap["http_TCP"]) + assert.Equal(t, int32(8080), portProtocolMap["http_UDP"]) + assert.Equal(t, int32(9090), portProtocolMap["metrics_TCP"]) + assert.Equal(t, int32(5353), portProtocolMap["dns_TCP"]) +} + +// TestExtractPortsFromSidecarWithServicePorts tests port extraction with both container and service ports. +func TestExtractPortsFromSidecarWithServicePorts(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 8080, + ContainerPortName: "http", + ServicePort: 80, + ServicePortName: "web", + Protocol: types.ProtoTCP, + AgentPort: 8081, + }, + { + ContainerPort: 9090, + ContainerPortName: "metrics", + ServicePort: 9000, + ServicePortName: "metrics-svc", + Protocol: types.ProtoTCP, + AgentPort: 9091, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + require.Len(t, ports, 2) + portMap := make(map[int32]*rpc.WorkloadPortInfo) + for _, p := range ports { + portMap[p.ContainerPort] = p + } + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "http", + ContainerPort: 8080, + Protocol: "TCP", + ServicePortName: "web", + ServicePort: 80, + }, portMap[8080]) + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "metrics", + ContainerPort: 9090, + Protocol: "TCP", + ServicePortName: "metrics-svc", + ServicePort: 9000, + }, portMap[9090]) +} + +// TestExtractPortsFromSidecarHeadlessService tests port extraction for headless services (no service port). +func TestExtractPortsFromSidecarHeadlessService(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 8080, + ContainerPortName: "http", + ServicePort: 0, // Headless service has no service port + ServicePortName: "", + Protocol: types.ProtoTCP, + AgentPort: 8081, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + require.Len(t, ports, 1) + assert.Equal(t, &rpc.WorkloadPortInfo{ + ContainerPortName: "http", + ContainerPort: 8080, + Protocol: "TCP", + ServicePortName: "", + ServicePort: 0, + }, ports[0]) +} + +// TestPortAndProtoAsMapKey tests that types.PortAndProto works correctly as a map key. +func TestPortAndProtoAsMapKey(t *testing.T) { + key1 := types.PortAndProto{Port: 8080, Proto: types.ProtoTCP} + key2 := types.PortAndProto{Port: 8080, Proto: types.ProtoTCP} + key3 := types.PortAndProto{Port: 8080, Proto: types.ProtoUDP} + + m := make(map[types.PortAndProto]bool) + m[key1] = true + + // Same port and protocol should be found + assert.True(t, m[key2]) + + // Different protocol should not be found + assert.False(t, m[key3]) + + // Add the third key + m[key3] = true + assert.True(t, m[key3]) +} + +// TestExtractPortsFromSidecarProtocolStrings tests that protocol is correctly converted to string. +func TestExtractPortsFromSidecarProtocolStrings(t *testing.T) { + ctx := dlog.NewTestContext(t, false) + + testCases := []struct { + name string + protocol types.Proto + expected string + }{ + { + name: "TCP protocol", + protocol: types.ProtoTCP, + expected: "TCP", + }, + { + name: "UDP protocol", + protocol: types.ProtoUDP, + expected: "UDP", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + sc := &agentconfig.Sidecar{ + Containers: []*agentconfig.Container{ + { + Name: "app", + Intercepts: []*agentconfig.Intercept{ + { + ContainerPort: 8080, + ContainerPortName: "test", + Protocol: tc.protocol, + AgentPort: 8081, + }, + }, + }, + }, + } + ports := extractPortsFromSidecar(ctx, sc) + require.Len(t, ports, 1) + assert.Equal(t, tc.expected, ports[0].Protocol) + }) + } +} diff --git a/docs/reference/cli/telepresence_genyaml_config.md b/docs/reference/cli/telepresence_genyaml_config.md index 4fec531196..e47c98b352 100644 --- a/docs/reference/cli/telepresence_genyaml_config.md +++ b/docs/reference/cli/telepresence_genyaml_config.md @@ -17,7 +17,7 @@ Generate YAML for the agent's entry in the telepresence-agents configmap. See ge ### Flags: ``` - --agent-image string The qualified name of the agent image (default "ghcr.io/telepresenceio/tel2:2.26.0") + --agent-image string The qualified name of the agent image (default "ghcr.io/telepresenceio/tel2:2.27.0") --agent-port uint16 The port number you wish the agent to listen on. (default 9900) -h, --help help for config -i, --input string Path to the yaml containing the workload definition (i.e. Deployment, StatefulSet, etc). Pass '-' for stdin.. Mutually exclusive to --workload diff --git a/docs/release-notes.md b/docs/release-notes.md index b9a0358e4d..7d6c11fb0b 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,13 @@ [comment]: # (Code generated by relnotesgen. DO NOT EDIT.) # Telepresence Release Notes +## Version 2.27.0 +##
feature
[Port Information in List Output](reference/client/list)
+
+ +The `telepresence list` command now includes comprehensive port information for each workload in multiple output formats. This enhancement allows developers to see which ports are available on interceptable workloads without needing to use `kubectl`. The port information includes both container ports (always present) and service ports (when available), along with protocol (TCP/UDP) and optional port names. This correctly handles headless services (container ports only) and replacement intercepts (which target container ports). This is particularly useful for VS Code extensions and other tools that need to display port information to users. +
+ ## Version 2.26.0 ##
feature
[Add configuration to disable global TCP/UDP intercepts](reference/cluster_config#restricting_global_intercepts)
diff --git a/docs/release-notes.mdx b/docs/release-notes.mdx index fc32e28d5f..c06e40c232 100644 --- a/docs/release-notes.mdx +++ b/docs/release-notes.mdx @@ -7,6 +7,13 @@ import { Note, Title, Body } from '@site/src/components/ReleaseNotes' [comment]: # (Code generated by relnotesgen. DO NOT EDIT.) # Telepresence Release Notes +## Version 2.27.0 + + Port Information in List Output + +The `telepresence list` command now includes comprehensive port information for each workload in multiple output formats. This enhancement allows developers to see which ports are available on interceptable workloads without needing to use `kubectl`. The port information includes both container ports (always present) and service ports (when available), along with protocol (TCP/UDP) and optional port names. This correctly handles headless services (container ports only) and replacement intercepts (which target container ports). This is particularly useful for VS Code extensions and other tools that need to display port information to users. + + ## Version 2.26.0 Add configuration to disable global TCP/UDP intercepts diff --git a/docs/variables.yml b/docs/variables.yml index 5deabc60cc..851c9d1592 100644 --- a/docs/variables.yml +++ b/docs/variables.yml @@ -1,2 +1,2 @@ -version: "2.26.0" -dlVersion: "v2.26.0" +version: "2.27.0" +dlVersion: "v2.27.0" diff --git a/integration_test/workload_ports_test.go b/integration_test/workload_ports_test.go new file mode 100644 index 0000000000..1ffc82ffe8 --- /dev/null +++ b/integration_test/workload_ports_test.go @@ -0,0 +1,171 @@ +package integration_test + +import ( + "encoding/json" + "time" + + "github.com/telepresenceio/telepresence/rpc/v2/connector" + "github.com/telepresenceio/telepresence/v2/integration_test/itest" +) + +type workloadPortsSuite struct { + itest.Suite + itest.TrafficManager +} + +func (s *workloadPortsSuite) SuiteName() string { + return "WorkloadPorts" +} + +func init() { + itest.AddTrafficManagerSuite("-workload-ports", func(h itest.TrafficManager) itest.TestingSuite { + return &workloadPortsSuite{Suite: itest.Suite{Harness: h}, TrafficManager: h} + }) +} + +// SetupSuite creates workloads BEFORE connecting telepresence +// This ensures workloads are in the initial WatchWorkloads snapshot +func (s *workloadPortsSuite) SetupSuite() { + s.Suite.SetupSuite() + + ctx := s.Context() + + // Deploy echo-easy (Deployment with normal service) + s.ApplyApp(ctx, "echo-easy", "deploy/echo-easy") + + // Deploy echo-headless (StatefulSet with headless service) + s.ApplyApp(ctx, "echo-headless", "statefulset/echo-headless") + + // Wait for workloads to be ready + s.Eventually(func() bool { + deployReady, err := s.KubectlOut(ctx, "get", "deploy/echo-easy", "-o", "jsonpath={.status.readyReplicas}") + if err != nil || deployReady != "1" { + return false + } + + stsReady, err := s.KubectlOut(ctx, "get", "statefulset/echo-headless", "-o", "jsonpath={.status.readyReplicas}") + return err == nil && stsReady == "1" + }, 3*time.Minute, 3*time.Second) + + // NOW connect telepresence - workloads already exist and will be in initial snapshot + s.TelepresenceConnect(ctx) +} + +func (s *workloadPortsSuite) TearDownSuite() { + ctx := s.Context() + + itest.TelepresenceDisconnectOk(ctx) + + // Clean up workloads + s.DeleteSvcAndWorkload(ctx, "deploy", "echo-easy") + s.DeleteSvcAndWorkload(ctx, "statefulset", "echo-headless") +} + +func (s *workloadPortsSuite) Test_ListWithPorts() { + ctx := s.Context() + + // Get the list output as JSON + stdout, stderr, err := itest.Telepresence(ctx, "list", "--output", "json") + s.Require().NoErrorf(err, "telepresence list failed: %s", stderr) + + // Parse the JSON response + var snapshot connector.WorkloadInfoSnapshot + s.Require().NoError(json.Unmarshal([]byte(stdout), &snapshot)) + + // Find the echo-easy workload + var foundWorkload *connector.WorkloadInfo + for _, workload := range snapshot.Workloads { + if workload.Name == "echo-easy" { + foundWorkload = workload + break + } + } + + s.Require().NotNil(foundWorkload, "workload echo-easy not found in list output") + + // Verify that the workload has ports information + s.Require().NotEmpty(foundWorkload.Ports, "workload should have ports information") + + // Verify each port has the required fields + for _, port := range foundWorkload.Ports { + s.Require().Greater(port.ContainerPort, int32(0), "container port number should be greater than 0") + s.Require().NotEmpty(port.Protocol, "port protocol should not be empty") + } +} + +func (s *workloadPortsSuite) Test_ListWithServicePorts() { + ctx := s.Context() + + // Get the list output as JSON + stdout, stderr, err := itest.Telepresence(ctx, "list", "--output", "json") + s.Require().NoErrorf(err, "telepresence list failed: %s", stderr) + + // Parse the JSON response + var snapshot connector.WorkloadInfoSnapshot + s.Require().NoError(json.Unmarshal([]byte(stdout), &snapshot)) + + // Find the echo-easy workload + var foundWorkload *connector.WorkloadInfo + for _, workload := range snapshot.Workloads { + if workload.Name == "echo-easy" { + foundWorkload = workload + break + } + } + + s.Require().NotNil(foundWorkload, "workload echo-easy not found in list output") + s.Require().NotEmpty(foundWorkload.Ports, "workload should have ports information") + + // Verify that both container and service port fields are present + // For a normal service (not headless), we expect service ports to be populated + hasServicePort := false + for _, port := range foundWorkload.Ports { + s.Require().Greater(port.ContainerPort, int32(0), "container port should be greater than 0") + s.Require().NotEmpty(port.Protocol, "protocol should not be empty") + + // For a service with port mapping, service port should be populated + // (it may be 0 for headless services, but echo-easy has a normal service) + if port.ServicePort > 0 { + hasServicePort = true + } + } + + // echo-easy has a normal service, so at least one port should have a service port + s.True(hasServicePort, "workload with a normal service should have at least one service port populated") +} + +func (s *workloadPortsSuite) Test_ListWithHeadlessServicePorts() { + ctx := s.Context() + + // Get the list output as JSON + stdout, stderr, err := itest.Telepresence(ctx, "list", "--output", "json") + s.Require().NoErrorf(err, "telepresence list failed: %s", stderr) + + // Parse the JSON response + var snapshot connector.WorkloadInfoSnapshot + s.Require().NoError(json.Unmarshal([]byte(stdout), &snapshot)) + + // Find the echo-headless workload + var foundWorkload *connector.WorkloadInfo + for _, workload := range snapshot.Workloads { + if workload.Name == "echo-headless" { + foundWorkload = workload + break + } + } + + s.Require().NotNil(foundWorkload, "workload echo-headless not found in list output") + s.Require().NotEmpty(foundWorkload.Ports, "headless workload should have ports information") + + // Verify that container ports are always present + // For headless services, the behavior may vary: + // - Container ports are always populated (mandatory) + // - Service ports might be 0 or might match container ports depending on implementation + for _, port := range foundWorkload.Ports { + s.Require().Greater(port.ContainerPort, int32(0), "container port should always be greater than 0") + s.Require().NotEmpty(port.Protocol, "protocol should not be empty") + } + + // The key assertion: container ports must be present for headless services + s.GreaterOrEqual(len(foundWorkload.Ports), 1, "headless service should have at least one container port") +} diff --git a/pkg/client/userd/trafficmgr/session.go b/pkg/client/userd/trafficmgr/session.go index 714005b64a..a01d8203c4 100644 --- a/pkg/client/userd/trafficmgr/session.go +++ b/pkg/client/userd/trafficmgr/session.go @@ -75,6 +75,7 @@ type workloadInfo struct { state workload.State agentState manager.WorkloadInfo_AgentState interceptClients []string + ports []*manager.WorkloadPortInfo } type session struct { @@ -473,6 +474,7 @@ func (s *session) getInfosForWorkloads( Namespace: namespace, WorkloadResourceType: kind, Uid: string(info.uid), + Ports: info.ports, } if info.state != workload.StateAvailable { wlInfo.NotInterceptableReason = info.state.String() @@ -992,6 +994,7 @@ func (s *session) workloadsWatcher(namespace string, synced *sync.WaitGroup) err state: state, agentState: w.AgentState, interceptClients: clients, + ports: w.Ports, } } } diff --git a/rpc/connector/connector.pb.go b/rpc/connector/connector.pb.go index a1c6255940..aa7b85cb0e 100644 --- a/rpc/connector/connector.pb.go +++ b/rpc/connector/connector.pb.go @@ -1089,8 +1089,10 @@ type WorkloadInfo struct { WorkloadResourceType string `protobuf:"bytes,6,opt,name=workload_resource_type,json=workloadResourceType,proto3" json:"workload_resource_type,omitempty"` Uid string `protobuf:"bytes,7,opt,name=uid,proto3" json:"uid,omitempty"` AgentVersion string `protobuf:"bytes,8,opt,name=agent_version,json=agentVersion,proto3" json:"agent_version,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Ports exposed by containers in this workload + Ports []*manager.WorkloadPortInfo `protobuf:"bytes,9,rep,name=ports,proto3" json:"ports,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *WorkloadInfo) Reset() { @@ -1179,6 +1181,13 @@ func (x *WorkloadInfo) GetAgentVersion() string { return "" } +func (x *WorkloadInfo) GetPorts() []*manager.WorkloadPortInfo { + if x != nil { + return x.Ports + } + return nil +} + type WorkloadInfoSnapshot struct { state protoimpl.MessageState `protogen:"open.v1"` Workloads []*WorkloadInfo `protobuf:"bytes,1,rep,name=workloads,proto3" json:"workloads,omitempty"` @@ -1846,7 +1855,7 @@ const file_connector_connector_proto_rawDesc = "" + "\x15WatchWorkloadsRequest\x12\x1e\n" + "\n" + "namespaces\x18\x01 \x03(\tR\n" + - "namespaces\"\xf8\x02\n" + + "namespaces\"\xb6\x03\n" + "\fWorkloadInfo\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1c\n" + "\tnamespace\x18\x02 \x01(\tR\tnamespace\x128\n" + @@ -1856,7 +1865,8 @@ const file_connector_connector_proto_rawDesc = "" + "ingestInfo\x124\n" + "\x16workload_resource_type\x18\x06 \x01(\tR\x14workloadResourceType\x12\x10\n" + "\x03uid\x18\a \x01(\tR\x03uid\x12#\n" + - "\ragent_version\x18\b \x01(\tR\fagentVersion\"Z\n" + + "\ragent_version\x18\b \x01(\tR\fagentVersion\x12<\n" + + "\x05ports\x18\t \x03(\v2&.telepresence.manager.WorkloadPortInfoR\x05ports\"Z\n" + "\x14WorkloadInfoSnapshot\x12B\n" + "\tworkloads\x18\x01 \x03(\v2$.telepresence.connector.WorkloadInfoR\tworkloads\"\xe5\x01\n" + "\x0fLogLevelRequest\x12\x1b\n" + @@ -1995,22 +2005,23 @@ var file_connector_connector_proto_goTypes = []any{ (*daemon.DaemonStatus)(nil), // 36: telepresence.daemon.DaemonStatus (*manager.InterceptSpec)(nil), // 37: telepresence.manager.InterceptSpec (*manager.InterceptInfo)(nil), // 38: telepresence.manager.InterceptInfo - (*durationpb.Duration)(nil), // 39: google.protobuf.Duration - (*manager.IPNet)(nil), // 40: telepresence.manager.IPNet - (*emptypb.Empty)(nil), // 41: google.protobuf.Empty - (*manager.GetInterceptRequest)(nil), // 42: telepresence.manager.GetInterceptRequest - (*manager.RemoveInterceptRequest2)(nil), // 43: telepresence.manager.RemoveInterceptRequest2 - (*daemon.SetDNSExcludesRequest)(nil), // 44: telepresence.daemon.SetDNSExcludesRequest - (*daemon.SetDNSMappingsRequest)(nil), // 45: telepresence.daemon.SetDNSMappingsRequest - (*manager.AgentConfigRequest)(nil), // 46: telepresence.manager.AgentConfigRequest - (*daemon.LookupIPRequest)(nil), // 47: telepresence.daemon.LookupIPRequest - (*daemon.ResolvePortRequest)(nil), // 48: telepresence.daemon.ResolvePortRequest - (*daemon.ReroutePortRequest)(nil), // 49: telepresence.daemon.ReroutePortRequest - (*manager.AgentImageFQN)(nil), // 50: telepresence.manager.AgentImageFQN - (*manager.KnownWorkloadKinds)(nil), // 51: telepresence.manager.KnownWorkloadKinds - (*manager.AgentConfigResponse)(nil), // 52: telepresence.manager.AgentConfigResponse - (*daemon.LookupIPResponse)(nil), // 53: telepresence.daemon.LookupIPResponse - (*daemon.ResolvePortResponse)(nil), // 54: telepresence.daemon.ResolvePortResponse + (*manager.WorkloadPortInfo)(nil), // 39: telepresence.manager.WorkloadPortInfo + (*durationpb.Duration)(nil), // 40: google.protobuf.Duration + (*manager.IPNet)(nil), // 41: telepresence.manager.IPNet + (*emptypb.Empty)(nil), // 42: google.protobuf.Empty + (*manager.GetInterceptRequest)(nil), // 43: telepresence.manager.GetInterceptRequest + (*manager.RemoveInterceptRequest2)(nil), // 44: telepresence.manager.RemoveInterceptRequest2 + (*daemon.SetDNSExcludesRequest)(nil), // 45: telepresence.daemon.SetDNSExcludesRequest + (*daemon.SetDNSMappingsRequest)(nil), // 46: telepresence.daemon.SetDNSMappingsRequest + (*manager.AgentConfigRequest)(nil), // 47: telepresence.manager.AgentConfigRequest + (*daemon.LookupIPRequest)(nil), // 48: telepresence.daemon.LookupIPRequest + (*daemon.ResolvePortRequest)(nil), // 49: telepresence.daemon.ResolvePortRequest + (*daemon.ReroutePortRequest)(nil), // 50: telepresence.daemon.ReroutePortRequest + (*manager.AgentImageFQN)(nil), // 51: telepresence.manager.AgentImageFQN + (*manager.KnownWorkloadKinds)(nil), // 52: telepresence.manager.KnownWorkloadKinds + (*manager.AgentConfigResponse)(nil), // 53: telepresence.manager.AgentConfigResponse + (*daemon.LookupIPResponse)(nil), // 54: telepresence.daemon.LookupIPResponse + (*daemon.ResolvePortResponse)(nil), // 55: telepresence.daemon.ResolvePortResponse } var file_connector_connector_proto_depIdxs = []int32{ 24, // 0: telepresence.connector.ConnectRequest.kube_flags:type_name -> telepresence.connector.ConnectRequest.KubeFlagsEntry @@ -2033,87 +2044,88 @@ var file_connector_connector_proto_depIdxs = []int32{ 29, // 17: telepresence.connector.IngestInfo.mounts:type_name -> telepresence.connector.IngestInfo.MountsEntry 38, // 18: telepresence.connector.WorkloadInfo.intercept_info:type_name -> telepresence.manager.InterceptInfo 11, // 19: telepresence.connector.WorkloadInfo.ingest_info:type_name -> telepresence.connector.IngestInfo - 13, // 20: telepresence.connector.WorkloadInfoSnapshot.workloads:type_name -> telepresence.connector.WorkloadInfo - 39, // 21: telepresence.connector.LogLevelRequest.duration:type_name -> google.protobuf.Duration - 2, // 22: telepresence.connector.LogLevelRequest.scope:type_name -> telepresence.connector.LogLevelRequest.Scope - 30, // 23: telepresence.connector.LogsResponse.pod_info:type_name -> telepresence.connector.LogsResponse.PodInfoEntry - 40, // 24: telepresence.connector.ClusterSubnets.pod_subnets:type_name -> telepresence.manager.IPNet - 40, // 25: telepresence.connector.ClusterSubnets.svc_subnets:type_name -> telepresence.manager.IPNet - 41, // 26: telepresence.connector.Connector.Version:input_type -> google.protobuf.Empty - 41, // 27: telepresence.connector.Connector.RootDaemonVersion:input_type -> google.protobuf.Empty - 41, // 28: telepresence.connector.Connector.TrafficManagerVersion:input_type -> google.protobuf.Empty - 41, // 29: telepresence.connector.Connector.AgentImageFQN:input_type -> google.protobuf.Empty - 42, // 30: telepresence.connector.Connector.GetIntercept:input_type -> telepresence.manager.GetInterceptRequest - 4, // 31: telepresence.connector.Connector.Connect:input_type -> telepresence.connector.ConnectRequest - 41, // 32: telepresence.connector.Connector.Disconnect:input_type -> google.protobuf.Empty - 41, // 33: telepresence.connector.Connector.GetClusterSubnets:input_type -> google.protobuf.Empty - 41, // 34: telepresence.connector.Connector.Status:input_type -> google.protobuf.Empty - 7, // 35: telepresence.connector.Connector.CanIntercept:input_type -> telepresence.connector.CreateInterceptRequest - 10, // 36: telepresence.connector.Connector.Ingest:input_type -> telepresence.connector.IngestRequest - 9, // 37: telepresence.connector.Connector.GetIngest:input_type -> telepresence.connector.IngestIdentifier - 9, // 38: telepresence.connector.Connector.LeaveIngest:input_type -> telepresence.connector.IngestIdentifier - 7, // 39: telepresence.connector.Connector.CreateIntercept:input_type -> telepresence.connector.CreateInterceptRequest - 43, // 40: telepresence.connector.Connector.RemoveIntercept:input_type -> telepresence.manager.RemoveInterceptRequest2 - 6, // 41: telepresence.connector.Connector.Uninstall:input_type -> telepresence.connector.UninstallRequest - 8, // 42: telepresence.connector.Connector.List:input_type -> telepresence.connector.ListRequest - 12, // 43: telepresence.connector.Connector.WatchWorkloads:input_type -> telepresence.connector.WatchWorkloadsRequest - 15, // 44: telepresence.connector.Connector.SetLogLevel:input_type -> telepresence.connector.LogLevelRequest - 41, // 45: telepresence.connector.Connector.Quit:input_type -> google.protobuf.Empty - 16, // 46: telepresence.connector.Connector.GatherLogs:input_type -> telepresence.connector.LogsRequest - 3, // 47: telepresence.connector.Connector.AddInterceptor:input_type -> telepresence.connector.Interceptor - 3, // 48: telepresence.connector.Connector.RemoveInterceptor:input_type -> telepresence.connector.Interceptor - 18, // 49: telepresence.connector.Connector.GetNamespaces:input_type -> telepresence.connector.GetNamespacesRequest - 41, // 50: telepresence.connector.Connector.GetKnownWorkloadKinds:input_type -> google.protobuf.Empty - 41, // 51: telepresence.connector.Connector.RemoteMountAvailability:input_type -> google.protobuf.Empty - 41, // 52: telepresence.connector.Connector.GetConfig:input_type -> google.protobuf.Empty - 44, // 53: telepresence.connector.Connector.SetDNSExcludes:input_type -> telepresence.daemon.SetDNSExcludesRequest - 45, // 54: telepresence.connector.Connector.SetDNSMappings:input_type -> telepresence.daemon.SetDNSMappingsRequest - 46, // 55: telepresence.connector.Connector.GetAgentConfig:input_type -> telepresence.manager.AgentConfigRequest - 22, // 56: telepresence.connector.Connector.ResolveSyntheticIP:input_type -> telepresence.connector.ResolveSyntheticRequest - 47, // 57: telepresence.connector.Connector.LookupIP:input_type -> telepresence.daemon.LookupIPRequest - 48, // 58: telepresence.connector.Connector.ResolvePort:input_type -> telepresence.daemon.ResolvePortRequest - 49, // 59: telepresence.connector.Connector.RerouteLocalPort:input_type -> telepresence.daemon.ReroutePortRequest - 49, // 60: telepresence.connector.Connector.RerouteRemotePort:input_type -> telepresence.daemon.ReroutePortRequest - 32, // 61: telepresence.connector.Connector.Version:output_type -> telepresence.common.VersionInfo - 32, // 62: telepresence.connector.Connector.RootDaemonVersion:output_type -> telepresence.common.VersionInfo - 32, // 63: telepresence.connector.Connector.TrafficManagerVersion:output_type -> telepresence.common.VersionInfo - 50, // 64: telepresence.connector.Connector.AgentImageFQN:output_type -> telepresence.manager.AgentImageFQN - 38, // 65: telepresence.connector.Connector.GetIntercept:output_type -> telepresence.manager.InterceptInfo - 5, // 66: telepresence.connector.Connector.Connect:output_type -> telepresence.connector.ConnectInfo - 41, // 67: telepresence.connector.Connector.Disconnect:output_type -> google.protobuf.Empty - 21, // 68: telepresence.connector.Connector.GetClusterSubnets:output_type -> telepresence.connector.ClusterSubnets - 5, // 69: telepresence.connector.Connector.Status:output_type -> telepresence.connector.ConnectInfo - 41, // 70: telepresence.connector.Connector.CanIntercept:output_type -> google.protobuf.Empty - 11, // 71: telepresence.connector.Connector.Ingest:output_type -> telepresence.connector.IngestInfo - 11, // 72: telepresence.connector.Connector.GetIngest:output_type -> telepresence.connector.IngestInfo - 11, // 73: telepresence.connector.Connector.LeaveIngest:output_type -> telepresence.connector.IngestInfo - 38, // 74: telepresence.connector.Connector.CreateIntercept:output_type -> telepresence.manager.InterceptInfo - 41, // 75: telepresence.connector.Connector.RemoveIntercept:output_type -> google.protobuf.Empty - 41, // 76: telepresence.connector.Connector.Uninstall:output_type -> google.protobuf.Empty - 14, // 77: telepresence.connector.Connector.List:output_type -> telepresence.connector.WorkloadInfoSnapshot - 14, // 78: telepresence.connector.Connector.WatchWorkloads:output_type -> telepresence.connector.WorkloadInfoSnapshot - 41, // 79: telepresence.connector.Connector.SetLogLevel:output_type -> google.protobuf.Empty - 41, // 80: telepresence.connector.Connector.Quit:output_type -> google.protobuf.Empty - 17, // 81: telepresence.connector.Connector.GatherLogs:output_type -> telepresence.connector.LogsResponse - 41, // 82: telepresence.connector.Connector.AddInterceptor:output_type -> google.protobuf.Empty - 41, // 83: telepresence.connector.Connector.RemoveInterceptor:output_type -> google.protobuf.Empty - 19, // 84: telepresence.connector.Connector.GetNamespaces:output_type -> telepresence.connector.GetNamespacesResponse - 51, // 85: telepresence.connector.Connector.GetKnownWorkloadKinds:output_type -> telepresence.manager.KnownWorkloadKinds - 41, // 86: telepresence.connector.Connector.RemoteMountAvailability:output_type -> google.protobuf.Empty - 20, // 87: telepresence.connector.Connector.GetConfig:output_type -> telepresence.connector.ClientConfig - 41, // 88: telepresence.connector.Connector.SetDNSExcludes:output_type -> google.protobuf.Empty - 41, // 89: telepresence.connector.Connector.SetDNSMappings:output_type -> google.protobuf.Empty - 52, // 90: telepresence.connector.Connector.GetAgentConfig:output_type -> telepresence.manager.AgentConfigResponse - 23, // 91: telepresence.connector.Connector.ResolveSyntheticIP:output_type -> telepresence.connector.ResolveSyntheticResponse - 53, // 92: telepresence.connector.Connector.LookupIP:output_type -> telepresence.daemon.LookupIPResponse - 54, // 93: telepresence.connector.Connector.ResolvePort:output_type -> telepresence.daemon.ResolvePortResponse - 41, // 94: telepresence.connector.Connector.RerouteLocalPort:output_type -> google.protobuf.Empty - 41, // 95: telepresence.connector.Connector.RerouteRemotePort:output_type -> google.protobuf.Empty - 61, // [61:96] is the sub-list for method output_type - 26, // [26:61] is the sub-list for method input_type - 26, // [26:26] is the sub-list for extension type_name - 26, // [26:26] is the sub-list for extension extendee - 0, // [0:26] is the sub-list for field type_name + 39, // 20: telepresence.connector.WorkloadInfo.ports:type_name -> telepresence.manager.WorkloadPortInfo + 13, // 21: telepresence.connector.WorkloadInfoSnapshot.workloads:type_name -> telepresence.connector.WorkloadInfo + 40, // 22: telepresence.connector.LogLevelRequest.duration:type_name -> google.protobuf.Duration + 2, // 23: telepresence.connector.LogLevelRequest.scope:type_name -> telepresence.connector.LogLevelRequest.Scope + 30, // 24: telepresence.connector.LogsResponse.pod_info:type_name -> telepresence.connector.LogsResponse.PodInfoEntry + 41, // 25: telepresence.connector.ClusterSubnets.pod_subnets:type_name -> telepresence.manager.IPNet + 41, // 26: telepresence.connector.ClusterSubnets.svc_subnets:type_name -> telepresence.manager.IPNet + 42, // 27: telepresence.connector.Connector.Version:input_type -> google.protobuf.Empty + 42, // 28: telepresence.connector.Connector.RootDaemonVersion:input_type -> google.protobuf.Empty + 42, // 29: telepresence.connector.Connector.TrafficManagerVersion:input_type -> google.protobuf.Empty + 42, // 30: telepresence.connector.Connector.AgentImageFQN:input_type -> google.protobuf.Empty + 43, // 31: telepresence.connector.Connector.GetIntercept:input_type -> telepresence.manager.GetInterceptRequest + 4, // 32: telepresence.connector.Connector.Connect:input_type -> telepresence.connector.ConnectRequest + 42, // 33: telepresence.connector.Connector.Disconnect:input_type -> google.protobuf.Empty + 42, // 34: telepresence.connector.Connector.GetClusterSubnets:input_type -> google.protobuf.Empty + 42, // 35: telepresence.connector.Connector.Status:input_type -> google.protobuf.Empty + 7, // 36: telepresence.connector.Connector.CanIntercept:input_type -> telepresence.connector.CreateInterceptRequest + 10, // 37: telepresence.connector.Connector.Ingest:input_type -> telepresence.connector.IngestRequest + 9, // 38: telepresence.connector.Connector.GetIngest:input_type -> telepresence.connector.IngestIdentifier + 9, // 39: telepresence.connector.Connector.LeaveIngest:input_type -> telepresence.connector.IngestIdentifier + 7, // 40: telepresence.connector.Connector.CreateIntercept:input_type -> telepresence.connector.CreateInterceptRequest + 44, // 41: telepresence.connector.Connector.RemoveIntercept:input_type -> telepresence.manager.RemoveInterceptRequest2 + 6, // 42: telepresence.connector.Connector.Uninstall:input_type -> telepresence.connector.UninstallRequest + 8, // 43: telepresence.connector.Connector.List:input_type -> telepresence.connector.ListRequest + 12, // 44: telepresence.connector.Connector.WatchWorkloads:input_type -> telepresence.connector.WatchWorkloadsRequest + 15, // 45: telepresence.connector.Connector.SetLogLevel:input_type -> telepresence.connector.LogLevelRequest + 42, // 46: telepresence.connector.Connector.Quit:input_type -> google.protobuf.Empty + 16, // 47: telepresence.connector.Connector.GatherLogs:input_type -> telepresence.connector.LogsRequest + 3, // 48: telepresence.connector.Connector.AddInterceptor:input_type -> telepresence.connector.Interceptor + 3, // 49: telepresence.connector.Connector.RemoveInterceptor:input_type -> telepresence.connector.Interceptor + 18, // 50: telepresence.connector.Connector.GetNamespaces:input_type -> telepresence.connector.GetNamespacesRequest + 42, // 51: telepresence.connector.Connector.GetKnownWorkloadKinds:input_type -> google.protobuf.Empty + 42, // 52: telepresence.connector.Connector.RemoteMountAvailability:input_type -> google.protobuf.Empty + 42, // 53: telepresence.connector.Connector.GetConfig:input_type -> google.protobuf.Empty + 45, // 54: telepresence.connector.Connector.SetDNSExcludes:input_type -> telepresence.daemon.SetDNSExcludesRequest + 46, // 55: telepresence.connector.Connector.SetDNSMappings:input_type -> telepresence.daemon.SetDNSMappingsRequest + 47, // 56: telepresence.connector.Connector.GetAgentConfig:input_type -> telepresence.manager.AgentConfigRequest + 22, // 57: telepresence.connector.Connector.ResolveSyntheticIP:input_type -> telepresence.connector.ResolveSyntheticRequest + 48, // 58: telepresence.connector.Connector.LookupIP:input_type -> telepresence.daemon.LookupIPRequest + 49, // 59: telepresence.connector.Connector.ResolvePort:input_type -> telepresence.daemon.ResolvePortRequest + 50, // 60: telepresence.connector.Connector.RerouteLocalPort:input_type -> telepresence.daemon.ReroutePortRequest + 50, // 61: telepresence.connector.Connector.RerouteRemotePort:input_type -> telepresence.daemon.ReroutePortRequest + 32, // 62: telepresence.connector.Connector.Version:output_type -> telepresence.common.VersionInfo + 32, // 63: telepresence.connector.Connector.RootDaemonVersion:output_type -> telepresence.common.VersionInfo + 32, // 64: telepresence.connector.Connector.TrafficManagerVersion:output_type -> telepresence.common.VersionInfo + 51, // 65: telepresence.connector.Connector.AgentImageFQN:output_type -> telepresence.manager.AgentImageFQN + 38, // 66: telepresence.connector.Connector.GetIntercept:output_type -> telepresence.manager.InterceptInfo + 5, // 67: telepresence.connector.Connector.Connect:output_type -> telepresence.connector.ConnectInfo + 42, // 68: telepresence.connector.Connector.Disconnect:output_type -> google.protobuf.Empty + 21, // 69: telepresence.connector.Connector.GetClusterSubnets:output_type -> telepresence.connector.ClusterSubnets + 5, // 70: telepresence.connector.Connector.Status:output_type -> telepresence.connector.ConnectInfo + 42, // 71: telepresence.connector.Connector.CanIntercept:output_type -> google.protobuf.Empty + 11, // 72: telepresence.connector.Connector.Ingest:output_type -> telepresence.connector.IngestInfo + 11, // 73: telepresence.connector.Connector.GetIngest:output_type -> telepresence.connector.IngestInfo + 11, // 74: telepresence.connector.Connector.LeaveIngest:output_type -> telepresence.connector.IngestInfo + 38, // 75: telepresence.connector.Connector.CreateIntercept:output_type -> telepresence.manager.InterceptInfo + 42, // 76: telepresence.connector.Connector.RemoveIntercept:output_type -> google.protobuf.Empty + 42, // 77: telepresence.connector.Connector.Uninstall:output_type -> google.protobuf.Empty + 14, // 78: telepresence.connector.Connector.List:output_type -> telepresence.connector.WorkloadInfoSnapshot + 14, // 79: telepresence.connector.Connector.WatchWorkloads:output_type -> telepresence.connector.WorkloadInfoSnapshot + 42, // 80: telepresence.connector.Connector.SetLogLevel:output_type -> google.protobuf.Empty + 42, // 81: telepresence.connector.Connector.Quit:output_type -> google.protobuf.Empty + 17, // 82: telepresence.connector.Connector.GatherLogs:output_type -> telepresence.connector.LogsResponse + 42, // 83: telepresence.connector.Connector.AddInterceptor:output_type -> google.protobuf.Empty + 42, // 84: telepresence.connector.Connector.RemoveInterceptor:output_type -> google.protobuf.Empty + 19, // 85: telepresence.connector.Connector.GetNamespaces:output_type -> telepresence.connector.GetNamespacesResponse + 52, // 86: telepresence.connector.Connector.GetKnownWorkloadKinds:output_type -> telepresence.manager.KnownWorkloadKinds + 42, // 87: telepresence.connector.Connector.RemoteMountAvailability:output_type -> google.protobuf.Empty + 20, // 88: telepresence.connector.Connector.GetConfig:output_type -> telepresence.connector.ClientConfig + 42, // 89: telepresence.connector.Connector.SetDNSExcludes:output_type -> google.protobuf.Empty + 42, // 90: telepresence.connector.Connector.SetDNSMappings:output_type -> google.protobuf.Empty + 53, // 91: telepresence.connector.Connector.GetAgentConfig:output_type -> telepresence.manager.AgentConfigResponse + 23, // 92: telepresence.connector.Connector.ResolveSyntheticIP:output_type -> telepresence.connector.ResolveSyntheticResponse + 54, // 93: telepresence.connector.Connector.LookupIP:output_type -> telepresence.daemon.LookupIPResponse + 55, // 94: telepresence.connector.Connector.ResolvePort:output_type -> telepresence.daemon.ResolvePortResponse + 42, // 95: telepresence.connector.Connector.RerouteLocalPort:output_type -> google.protobuf.Empty + 42, // 96: telepresence.connector.Connector.RerouteRemotePort:output_type -> google.protobuf.Empty + 62, // [62:97] is the sub-list for method output_type + 27, // [27:62] is the sub-list for method input_type + 27, // [27:27] is the sub-list for extension type_name + 27, // [27:27] is the sub-list for extension extendee + 0, // [0:27] is the sub-list for field type_name } func init() { file_connector_connector_proto_init() } diff --git a/rpc/connector/connector.proto b/rpc/connector/connector.proto index dacbd03e1a..d7cf85cc96 100644 --- a/rpc/connector/connector.proto +++ b/rpc/connector/connector.proto @@ -335,6 +335,9 @@ message WorkloadInfo { string uid = 7; string agent_version = 8; + + // Ports exposed by containers in this workload + repeated manager.WorkloadPortInfo ports = 9; } message WorkloadInfoSnapshot { diff --git a/rpc/manager/manager.pb.go b/rpc/manager/manager.pb.go index 89df93e03a..eba84e1eed 100644 --- a/rpc/manager/manager.pb.go +++ b/rpc/manager/manager.pb.go @@ -169,7 +169,7 @@ func (x WorkloadInfo_Kind) Number() protoreflect.EnumNumber { // Deprecated: Use WorkloadInfo_Kind.Descriptor instead. func (WorkloadInfo_Kind) EnumDescriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{42, 0} + return file_manager_manager_proto_rawDescGZIP(), []int{43, 0} } type WorkloadInfo_State int32 @@ -229,7 +229,7 @@ func (x WorkloadInfo_State) Number() protoreflect.EnumNumber { // Deprecated: Use WorkloadInfo_State.Descriptor instead. func (WorkloadInfo_State) EnumDescriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{42, 1} + return file_manager_manager_proto_rawDescGZIP(), []int{43, 1} } type WorkloadInfo_AgentState int32 @@ -281,7 +281,7 @@ func (x WorkloadInfo_AgentState) Number() protoreflect.EnumNumber { // Deprecated: Use WorkloadInfo_AgentState.Descriptor instead. func (WorkloadInfo_AgentState) EnumDescriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{42, 2} + return file_manager_manager_proto_rawDescGZIP(), []int{43, 2} } type WorkloadEvent_Type int32 @@ -330,7 +330,7 @@ func (x WorkloadEvent_Type) Number() protoreflect.EnumNumber { // Deprecated: Use WorkloadEvent_Type.Descriptor instead. func (WorkloadEvent_Type) EnumDescriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{43, 0} + return file_manager_manager_proto_rawDescGZIP(), []int{44, 0} } // ClientInfo is the self-reported metadata that the on-laptop @@ -3351,6 +3351,88 @@ func (x *KnownWorkloadKinds) GetKinds() []WorkloadInfo_Kind { return nil } +// WorkloadPortInfo describes a port exposed by a workload's container +type WorkloadPortInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Symbolic name of the container port (e.g., "http", "grpc") + ContainerPortName string `protobuf:"bytes,1,opt,name=container_port_name,json=containerPortName,proto3" json:"container_port_name,omitempty"` + // Numeric container port number (mandatory, always present) + ContainerPort int32 `protobuf:"varint,2,opt,name=container_port,json=containerPort,proto3" json:"container_port,omitempty"` + // Protocol used by the port (TCP or UDP) + Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"` + // Symbolic name of the service port (may be empty for headless services or replacements) + ServicePortName string `protobuf:"bytes,4,opt,name=service_port_name,json=servicePortName,proto3" json:"service_port_name,omitempty"` + // Numeric service port number (may be 0 for headless services or replacements) + ServicePort int32 `protobuf:"varint,5,opt,name=service_port,json=servicePort,proto3" json:"service_port,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *WorkloadPortInfo) Reset() { + *x = WorkloadPortInfo{} + mi := &file_manager_manager_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *WorkloadPortInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*WorkloadPortInfo) ProtoMessage() {} + +func (x *WorkloadPortInfo) ProtoReflect() protoreflect.Message { + mi := &file_manager_manager_proto_msgTypes[42] + 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 WorkloadPortInfo.ProtoReflect.Descriptor instead. +func (*WorkloadPortInfo) Descriptor() ([]byte, []int) { + return file_manager_manager_proto_rawDescGZIP(), []int{42} +} + +func (x *WorkloadPortInfo) GetContainerPortName() string { + if x != nil { + return x.ContainerPortName + } + return "" +} + +func (x *WorkloadPortInfo) GetContainerPort() int32 { + if x != nil { + return x.ContainerPort + } + return 0 +} + +func (x *WorkloadPortInfo) GetProtocol() string { + if x != nil { + return x.Protocol + } + return "" +} + +func (x *WorkloadPortInfo) GetServicePortName() string { + if x != nil { + return x.ServicePortName + } + return "" +} + +func (x *WorkloadPortInfo) GetServicePort() int32 { + if x != nil { + return x.ServicePort + } + return 0 +} + // WorkloadInfo contains information about a workload (typically a // Deployment). type WorkloadInfo struct { @@ -3362,13 +3444,15 @@ type WorkloadInfo struct { AgentState WorkloadInfo_AgentState `protobuf:"varint,4,opt,name=agent_state,json=agentState,proto3,enum=telepresence.manager.WorkloadInfo_AgentState" json:"agent_state,omitempty"` InterceptClients []*WorkloadInfo_Intercept `protobuf:"bytes,5,rep,name=intercept_clients,json=interceptClients,proto3" json:"intercept_clients,omitempty"` State WorkloadInfo_State `protobuf:"varint,6,opt,name=state,proto3,enum=telepresence.manager.WorkloadInfo_State" json:"state,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // Ports exposed by containers in this workload + Ports []*WorkloadPortInfo `protobuf:"bytes,8,rep,name=ports,proto3" json:"ports,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *WorkloadInfo) Reset() { *x = WorkloadInfo{} - mi := &file_manager_manager_proto_msgTypes[42] + mi := &file_manager_manager_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3380,7 +3464,7 @@ func (x *WorkloadInfo) String() string { func (*WorkloadInfo) ProtoMessage() {} func (x *WorkloadInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[42] + mi := &file_manager_manager_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3393,7 +3477,7 @@ func (x *WorkloadInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadInfo.ProtoReflect.Descriptor instead. func (*WorkloadInfo) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{42} + return file_manager_manager_proto_rawDescGZIP(), []int{43} } func (x *WorkloadInfo) GetKind() WorkloadInfo_Kind { @@ -3445,6 +3529,13 @@ func (x *WorkloadInfo) GetState() WorkloadInfo_State { return WorkloadInfo_UNKNOWN_UNSPECIFIED } +func (x *WorkloadInfo) GetPorts() []*WorkloadPortInfo { + if x != nil { + return x.Ports + } + return nil +} + type WorkloadEvent struct { state protoimpl.MessageState `protogen:"open.v1"` Type WorkloadEvent_Type `protobuf:"varint,1,opt,name=type,proto3,enum=telepresence.manager.WorkloadEvent_Type" json:"type,omitempty"` @@ -3455,7 +3546,7 @@ type WorkloadEvent struct { func (x *WorkloadEvent) Reset() { *x = WorkloadEvent{} - mi := &file_manager_manager_proto_msgTypes[43] + mi := &file_manager_manager_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3467,7 +3558,7 @@ func (x *WorkloadEvent) String() string { func (*WorkloadEvent) ProtoMessage() {} func (x *WorkloadEvent) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[43] + mi := &file_manager_manager_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3480,7 +3571,7 @@ func (x *WorkloadEvent) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadEvent.ProtoReflect.Descriptor instead. func (*WorkloadEvent) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{43} + return file_manager_manager_proto_rawDescGZIP(), []int{44} } func (x *WorkloadEvent) GetType() WorkloadEvent_Type { @@ -3512,7 +3603,7 @@ type WorkloadEventsDelta struct { func (x *WorkloadEventsDelta) Reset() { *x = WorkloadEventsDelta{} - mi := &file_manager_manager_proto_msgTypes[44] + mi := &file_manager_manager_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3524,7 +3615,7 @@ func (x *WorkloadEventsDelta) String() string { func (*WorkloadEventsDelta) ProtoMessage() {} func (x *WorkloadEventsDelta) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[44] + mi := &file_manager_manager_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3537,7 +3628,7 @@ func (x *WorkloadEventsDelta) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadEventsDelta.ProtoReflect.Descriptor instead. func (*WorkloadEventsDelta) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{44} + return file_manager_manager_proto_rawDescGZIP(), []int{45} } func (x *WorkloadEventsDelta) GetSince() *timestamppb.Timestamp { @@ -3571,7 +3662,7 @@ type WorkloadEventsRequest struct { func (x *WorkloadEventsRequest) Reset() { *x = WorkloadEventsRequest{} - mi := &file_manager_manager_proto_msgTypes[45] + mi := &file_manager_manager_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3583,7 +3674,7 @@ func (x *WorkloadEventsRequest) String() string { func (*WorkloadEventsRequest) ProtoMessage() {} func (x *WorkloadEventsRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[45] + mi := &file_manager_manager_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3596,7 +3687,7 @@ func (x *WorkloadEventsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadEventsRequest.ProtoReflect.Descriptor instead. func (*WorkloadEventsRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{45} + return file_manager_manager_proto_rawDescGZIP(), []int{46} } func (x *WorkloadEventsRequest) GetSessionInfo() *SessionInfo { @@ -3633,7 +3724,7 @@ type UninstallAgentsRequest struct { func (x *UninstallAgentsRequest) Reset() { *x = UninstallAgentsRequest{} - mi := &file_manager_manager_proto_msgTypes[46] + mi := &file_manager_manager_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3645,7 +3736,7 @@ func (x *UninstallAgentsRequest) String() string { func (*UninstallAgentsRequest) ProtoMessage() {} func (x *UninstallAgentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[46] + mi := &file_manager_manager_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3658,7 +3749,7 @@ func (x *UninstallAgentsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UninstallAgentsRequest.ProtoReflect.Descriptor instead. func (*UninstallAgentsRequest) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{46} + return file_manager_manager_proto_rawDescGZIP(), []int{47} } func (x *UninstallAgentsRequest) GetSessionInfo() *SessionInfo { @@ -3697,7 +3788,7 @@ type AgentInfo_Mechanism struct { func (x *AgentInfo_Mechanism) Reset() { *x = AgentInfo_Mechanism{} - mi := &file_manager_manager_proto_msgTypes[47] + mi := &file_manager_manager_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3709,7 +3800,7 @@ func (x *AgentInfo_Mechanism) String() string { func (*AgentInfo_Mechanism) ProtoMessage() {} func (x *AgentInfo_Mechanism) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[47] + mi := &file_manager_manager_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3760,7 +3851,7 @@ type AgentInfo_ContainerInfo struct { func (x *AgentInfo_ContainerInfo) Reset() { *x = AgentInfo_ContainerInfo{} - mi := &file_manager_manager_proto_msgTypes[48] + mi := &file_manager_manager_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3772,7 +3863,7 @@ func (x *AgentInfo_ContainerInfo) String() string { func (*AgentInfo_ContainerInfo) ProtoMessage() {} func (x *AgentInfo_ContainerInfo) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[48] + mi := &file_manager_manager_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3819,7 +3910,7 @@ type WorkloadInfo_Intercept struct { func (x *WorkloadInfo_Intercept) Reset() { *x = WorkloadInfo_Intercept{} - mi := &file_manager_manager_proto_msgTypes[60] + mi := &file_manager_manager_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3831,7 +3922,7 @@ func (x *WorkloadInfo_Intercept) String() string { func (*WorkloadInfo_Intercept) ProtoMessage() {} func (x *WorkloadInfo_Intercept) ProtoReflect() protoreflect.Message { - mi := &file_manager_manager_proto_msgTypes[60] + mi := &file_manager_manager_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3844,7 +3935,7 @@ func (x *WorkloadInfo_Intercept) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadInfo_Intercept.ProtoReflect.Descriptor instead. func (*WorkloadInfo_Intercept) Descriptor() ([]byte, []int) { - return file_manager_manager_proto_rawDescGZIP(), []int{42, 0} + return file_manager_manager_proto_rawDescGZIP(), []int{43, 0} } func (x *WorkloadInfo_Intercept) GetClient() string { @@ -4152,7 +4243,13 @@ const file_manager_manager_proto_rawDesc = "" + "\ringress_bytes\x18\x02 \x01(\x04R\fingressBytes\x12!\n" + "\fegress_bytes\x18\x03 \x01(\x04R\vegressBytes\"S\n" + "\x12KnownWorkloadKinds\x12=\n" + - "\x05kinds\x18\x01 \x03(\x0e2'.telepresence.manager.WorkloadInfo.KindR\x05kinds\"\x8d\x05\n" + + "\x05kinds\x18\x01 \x03(\x0e2'.telepresence.manager.WorkloadInfo.KindR\x05kinds\"\xd4\x01\n" + + "\x10WorkloadPortInfo\x12.\n" + + "\x13container_port_name\x18\x01 \x01(\tR\x11containerPortName\x12%\n" + + "\x0econtainer_port\x18\x02 \x01(\x05R\rcontainerPort\x12\x1a\n" + + "\bprotocol\x18\x03 \x01(\tR\bprotocol\x12*\n" + + "\x11service_port_name\x18\x04 \x01(\tR\x0fservicePortName\x12!\n" + + "\fservice_port\x18\x05 \x01(\x05R\vservicePort\"\xcb\x05\n" + "\fWorkloadInfo\x12;\n" + "\x04kind\x18\x01 \x01(\x0e2'.telepresence.manager.WorkloadInfo.KindR\x04kind\x12\x12\n" + "\x04name\x18\x02 \x01(\tR\x04name\x12\x1c\n" + @@ -4161,7 +4258,8 @@ const file_manager_manager_proto_rawDesc = "" + "\vagent_state\x18\x04 \x01(\x0e2-.telepresence.manager.WorkloadInfo.AgentStateR\n" + "agentState\x12Y\n" + "\x11intercept_clients\x18\x05 \x03(\v2,.telepresence.manager.WorkloadInfo.InterceptR\x10interceptClients\x12>\n" + - "\x05state\x18\x06 \x01(\x0e2(.telepresence.manager.WorkloadInfo.StateR\x05state\x1a#\n" + + "\x05state\x18\x06 \x01(\x0e2(.telepresence.manager.WorkloadInfo.StateR\x05state\x12<\n" + + "\x05ports\x18\b \x03(\v2&.telepresence.manager.WorkloadPortInfoR\x05ports\x1a#\n" + "\tIntercept\x12\x16\n" + "\x06client\x18\x01 \x01(\tR\x06client\"U\n" + "\x04Kind\x12\x0f\n" + @@ -4257,7 +4355,7 @@ func file_manager_manager_proto_rawDescGZIP() []byte { } var file_manager_manager_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_manager_manager_proto_msgTypes = make([]protoimpl.MessageInfo, 61) +var file_manager_manager_proto_msgTypes = make([]protoimpl.MessageInfo, 62) var file_manager_manager_proto_goTypes = []any{ (InterceptDispositionType)(0), // 0: telepresence.manager.InterceptDispositionType (WorkloadInfo_Kind)(0), // 1: telepresence.manager.WorkloadInfo.Kind @@ -4306,40 +4404,41 @@ var file_manager_manager_proto_goTypes = []any{ (*AgentConfigResponse)(nil), // 44: telepresence.manager.AgentConfigResponse (*TunnelMetrics)(nil), // 45: telepresence.manager.TunnelMetrics (*KnownWorkloadKinds)(nil), // 46: telepresence.manager.KnownWorkloadKinds - (*WorkloadInfo)(nil), // 47: telepresence.manager.WorkloadInfo - (*WorkloadEvent)(nil), // 48: telepresence.manager.WorkloadEvent - (*WorkloadEventsDelta)(nil), // 49: telepresence.manager.WorkloadEventsDelta - (*WorkloadEventsRequest)(nil), // 50: telepresence.manager.WorkloadEventsRequest - (*UninstallAgentsRequest)(nil), // 51: telepresence.manager.UninstallAgentsRequest - (*AgentInfo_Mechanism)(nil), // 52: telepresence.manager.AgentInfo.Mechanism - (*AgentInfo_ContainerInfo)(nil), // 53: telepresence.manager.AgentInfo.ContainerInfo - nil, // 54: telepresence.manager.AgentInfo.ContainersEntry - nil, // 55: telepresence.manager.AgentInfo.ContainerInfo.EnvironmentEntry - nil, // 56: telepresence.manager.AgentInfo.ContainerInfo.MountsEntry - nil, // 57: telepresence.manager.InterceptSpec.HeaderFiltersEntry - nil, // 58: telepresence.manager.InterceptSpec.MetadataEntry - nil, // 59: telepresence.manager.InterceptInfo.EnvironmentEntry - nil, // 60: telepresence.manager.InterceptInfo.MountsEntry - nil, // 61: telepresence.manager.ReviewInterceptRequest.EnvironmentEntry - nil, // 62: telepresence.manager.ReviewInterceptRequest.MountsEntry - nil, // 63: telepresence.manager.LogsResponse.PodLogsEntry - nil, // 64: telepresence.manager.LogsResponse.PodYamlEntry - (*WorkloadInfo_Intercept)(nil), // 65: telepresence.manager.WorkloadInfo.Intercept - (*timestamppb.Timestamp)(nil), // 66: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 67: google.protobuf.Duration - (*emptypb.Empty)(nil), // 68: google.protobuf.Empty + (*WorkloadPortInfo)(nil), // 47: telepresence.manager.WorkloadPortInfo + (*WorkloadInfo)(nil), // 48: telepresence.manager.WorkloadInfo + (*WorkloadEvent)(nil), // 49: telepresence.manager.WorkloadEvent + (*WorkloadEventsDelta)(nil), // 50: telepresence.manager.WorkloadEventsDelta + (*WorkloadEventsRequest)(nil), // 51: telepresence.manager.WorkloadEventsRequest + (*UninstallAgentsRequest)(nil), // 52: telepresence.manager.UninstallAgentsRequest + (*AgentInfo_Mechanism)(nil), // 53: telepresence.manager.AgentInfo.Mechanism + (*AgentInfo_ContainerInfo)(nil), // 54: telepresence.manager.AgentInfo.ContainerInfo + nil, // 55: telepresence.manager.AgentInfo.ContainersEntry + nil, // 56: telepresence.manager.AgentInfo.ContainerInfo.EnvironmentEntry + nil, // 57: telepresence.manager.AgentInfo.ContainerInfo.MountsEntry + nil, // 58: telepresence.manager.InterceptSpec.HeaderFiltersEntry + nil, // 59: telepresence.manager.InterceptSpec.MetadataEntry + nil, // 60: telepresence.manager.InterceptInfo.EnvironmentEntry + nil, // 61: telepresence.manager.InterceptInfo.MountsEntry + nil, // 62: telepresence.manager.ReviewInterceptRequest.EnvironmentEntry + nil, // 63: telepresence.manager.ReviewInterceptRequest.MountsEntry + nil, // 64: telepresence.manager.LogsResponse.PodLogsEntry + nil, // 65: telepresence.manager.LogsResponse.PodYamlEntry + (*WorkloadInfo_Intercept)(nil), // 66: telepresence.manager.WorkloadInfo.Intercept + (*timestamppb.Timestamp)(nil), // 67: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 68: google.protobuf.Duration + (*emptypb.Empty)(nil), // 69: google.protobuf.Empty } var file_manager_manager_proto_depIdxs = []int32{ - 52, // 0: telepresence.manager.AgentInfo.mechanisms:type_name -> telepresence.manager.AgentInfo.Mechanism - 54, // 1: telepresence.manager.AgentInfo.containers:type_name -> telepresence.manager.AgentInfo.ContainersEntry - 57, // 2: telepresence.manager.InterceptSpec.header_filters:type_name -> telepresence.manager.InterceptSpec.HeaderFiltersEntry - 58, // 3: telepresence.manager.InterceptSpec.metadata:type_name -> telepresence.manager.InterceptSpec.MetadataEntry + 53, // 0: telepresence.manager.AgentInfo.mechanisms:type_name -> telepresence.manager.AgentInfo.Mechanism + 55, // 1: telepresence.manager.AgentInfo.containers:type_name -> telepresence.manager.AgentInfo.ContainersEntry + 58, // 2: telepresence.manager.InterceptSpec.header_filters:type_name -> telepresence.manager.InterceptSpec.HeaderFiltersEntry + 59, // 3: telepresence.manager.InterceptSpec.metadata:type_name -> telepresence.manager.InterceptSpec.MetadataEntry 8, // 4: telepresence.manager.InterceptInfo.spec:type_name -> telepresence.manager.InterceptSpec 12, // 5: telepresence.manager.InterceptInfo.client_session:type_name -> telepresence.manager.SessionInfo 0, // 6: telepresence.manager.InterceptInfo.disposition:type_name -> telepresence.manager.InterceptDispositionType - 59, // 7: telepresence.manager.InterceptInfo.environment:type_name -> telepresence.manager.InterceptInfo.EnvironmentEntry - 60, // 8: telepresence.manager.InterceptInfo.mounts:type_name -> telepresence.manager.InterceptInfo.MountsEntry - 66, // 9: telepresence.manager.InterceptInfo.modified_at:type_name -> google.protobuf.Timestamp + 60, // 7: telepresence.manager.InterceptInfo.environment:type_name -> telepresence.manager.InterceptInfo.EnvironmentEntry + 61, // 8: telepresence.manager.InterceptInfo.mounts:type_name -> telepresence.manager.InterceptInfo.MountsEntry + 67, // 9: telepresence.manager.InterceptInfo.modified_at:type_name -> google.protobuf.Timestamp 12, // 10: telepresence.manager.ReconnectAgentRequest.session:type_name -> telepresence.manager.SessionInfo 6, // 11: telepresence.manager.ReconnectAgentRequest.agent:type_name -> telepresence.manager.AgentInfo 12, // 12: telepresence.manager.ReconnectClientRequest.session:type_name -> telepresence.manager.SessionInfo @@ -4356,12 +4455,12 @@ var file_manager_manager_proto_depIdxs = []int32{ 12, // 23: telepresence.manager.GetInterceptRequest.session:type_name -> telepresence.manager.SessionInfo 12, // 24: telepresence.manager.ReviewInterceptRequest.session:type_name -> telepresence.manager.SessionInfo 0, // 25: telepresence.manager.ReviewInterceptRequest.disposition:type_name -> telepresence.manager.InterceptDispositionType - 61, // 26: telepresence.manager.ReviewInterceptRequest.environment:type_name -> telepresence.manager.ReviewInterceptRequest.EnvironmentEntry - 62, // 27: telepresence.manager.ReviewInterceptRequest.mounts:type_name -> telepresence.manager.ReviewInterceptRequest.MountsEntry + 62, // 26: telepresence.manager.ReviewInterceptRequest.environment:type_name -> telepresence.manager.ReviewInterceptRequest.EnvironmentEntry + 63, // 27: telepresence.manager.ReviewInterceptRequest.mounts:type_name -> telepresence.manager.ReviewInterceptRequest.MountsEntry 12, // 28: telepresence.manager.RemainRequest.session:type_name -> telepresence.manager.SessionInfo - 67, // 29: telepresence.manager.LogLevelRequest.duration:type_name -> google.protobuf.Duration - 63, // 30: telepresence.manager.LogsResponse.pod_logs:type_name -> telepresence.manager.LogsResponse.PodLogsEntry - 64, // 31: telepresence.manager.LogsResponse.pod_yaml:type_name -> telepresence.manager.LogsResponse.PodYamlEntry + 68, // 29: telepresence.manager.LogLevelRequest.duration:type_name -> google.protobuf.Duration + 64, // 30: telepresence.manager.LogsResponse.pod_logs:type_name -> telepresence.manager.LogsResponse.PodLogsEntry + 65, // 31: telepresence.manager.LogsResponse.pod_yaml:type_name -> telepresence.manager.LogsResponse.PodYamlEntry 12, // 32: telepresence.manager.LookupRequest.session:type_name -> telepresence.manager.SessionInfo 12, // 33: telepresence.manager.DNSRequest.session:type_name -> telepresence.manager.SessionInfo 12, // 34: telepresence.manager.DNSAgentResponse.session:type_name -> telepresence.manager.SessionInfo @@ -4379,85 +4478,86 @@ var file_manager_manager_proto_depIdxs = []int32{ 1, // 46: telepresence.manager.KnownWorkloadKinds.kinds:type_name -> telepresence.manager.WorkloadInfo.Kind 1, // 47: telepresence.manager.WorkloadInfo.kind:type_name -> telepresence.manager.WorkloadInfo.Kind 3, // 48: telepresence.manager.WorkloadInfo.agent_state:type_name -> telepresence.manager.WorkloadInfo.AgentState - 65, // 49: telepresence.manager.WorkloadInfo.intercept_clients:type_name -> telepresence.manager.WorkloadInfo.Intercept + 66, // 49: telepresence.manager.WorkloadInfo.intercept_clients:type_name -> telepresence.manager.WorkloadInfo.Intercept 2, // 50: telepresence.manager.WorkloadInfo.state:type_name -> telepresence.manager.WorkloadInfo.State - 4, // 51: telepresence.manager.WorkloadEvent.type:type_name -> telepresence.manager.WorkloadEvent.Type - 47, // 52: telepresence.manager.WorkloadEvent.workload:type_name -> telepresence.manager.WorkloadInfo - 66, // 53: telepresence.manager.WorkloadEventsDelta.since:type_name -> google.protobuf.Timestamp - 48, // 54: telepresence.manager.WorkloadEventsDelta.events:type_name -> telepresence.manager.WorkloadEvent - 12, // 55: telepresence.manager.WorkloadEventsRequest.session_info:type_name -> telepresence.manager.SessionInfo - 66, // 56: telepresence.manager.WorkloadEventsRequest.since:type_name -> google.protobuf.Timestamp - 12, // 57: telepresence.manager.UninstallAgentsRequest.session_info:type_name -> telepresence.manager.SessionInfo - 55, // 58: telepresence.manager.AgentInfo.ContainerInfo.environment:type_name -> telepresence.manager.AgentInfo.ContainerInfo.EnvironmentEntry - 56, // 59: telepresence.manager.AgentInfo.ContainerInfo.mounts:type_name -> telepresence.manager.AgentInfo.ContainerInfo.MountsEntry - 53, // 60: telepresence.manager.AgentInfo.ContainersEntry.value:type_name -> telepresence.manager.AgentInfo.ContainerInfo - 68, // 61: telepresence.manager.Manager.Version:input_type -> google.protobuf.Empty - 68, // 62: telepresence.manager.Manager.GetAgentImageFQN:input_type -> google.protobuf.Empty - 43, // 63: telepresence.manager.Manager.GetAgentConfig:input_type -> telepresence.manager.AgentConfigRequest - 68, // 64: telepresence.manager.Manager.GetClientConfig:input_type -> google.protobuf.Empty - 68, // 65: telepresence.manager.Manager.GetTelepresenceAPI:input_type -> google.protobuf.Empty - 5, // 66: telepresence.manager.Manager.ArriveAsClient:input_type -> telepresence.manager.ClientInfo - 10, // 67: telepresence.manager.Manager.ReconnectAgent:input_type -> telepresence.manager.ReconnectAgentRequest - 11, // 68: telepresence.manager.Manager.ReconnectClient:input_type -> telepresence.manager.ReconnectClientRequest - 6, // 69: telepresence.manager.Manager.ArriveAsAgent:input_type -> telepresence.manager.AgentInfo - 22, // 70: telepresence.manager.Manager.Remain:input_type -> telepresence.manager.RemainRequest - 12, // 71: telepresence.manager.Manager.Depart:input_type -> telepresence.manager.SessionInfo - 23, // 72: telepresence.manager.Manager.SetLogLevel:input_type -> telepresence.manager.LogLevelRequest - 24, // 73: telepresence.manager.Manager.GetLogs:input_type -> telepresence.manager.GetLogsRequest - 12, // 74: telepresence.manager.Manager.WatchAgentPods:input_type -> telepresence.manager.SessionInfo - 12, // 75: telepresence.manager.Manager.WatchAgents:input_type -> telepresence.manager.SessionInfo - 12, // 76: telepresence.manager.Manager.WatchIntercepts:input_type -> telepresence.manager.SessionInfo - 50, // 77: telepresence.manager.Manager.WatchWorkloads:input_type -> telepresence.manager.WorkloadEventsRequest - 12, // 78: telepresence.manager.Manager.WatchClusterInfo:input_type -> telepresence.manager.SessionInfo - 17, // 79: telepresence.manager.Manager.EnsureAgent:input_type -> telepresence.manager.EnsureAgentRequest - 16, // 80: telepresence.manager.Manager.PrepareIntercept:input_type -> telepresence.manager.CreateInterceptRequest - 16, // 81: telepresence.manager.Manager.CreateIntercept:input_type -> telepresence.manager.CreateInterceptRequest - 19, // 82: telepresence.manager.Manager.RemoveIntercept:input_type -> telepresence.manager.RemoveInterceptRequest2 - 20, // 83: telepresence.manager.Manager.GetIntercept:input_type -> telepresence.manager.GetInterceptRequest - 21, // 84: telepresence.manager.Manager.ReviewIntercept:input_type -> telepresence.manager.ReviewInterceptRequest - 12, // 85: telepresence.manager.Manager.GetKnownWorkloadKinds:input_type -> telepresence.manager.SessionInfo - 30, // 86: telepresence.manager.Manager.Lookup:input_type -> telepresence.manager.LookupRequest - 32, // 87: telepresence.manager.Manager.LookupDNS:input_type -> telepresence.manager.DNSRequest - 68, // 88: telepresence.manager.Manager.WatchLogLevel:input_type -> google.protobuf.Empty - 28, // 89: telepresence.manager.Manager.Tunnel:input_type -> telepresence.manager.TunnelMessage - 45, // 90: telepresence.manager.Manager.ReportMetrics:input_type -> telepresence.manager.TunnelMetrics - 51, // 91: telepresence.manager.Manager.UninstallAgents:input_type -> telepresence.manager.UninstallAgentsRequest - 27, // 92: telepresence.manager.Manager.Version:output_type -> telepresence.manager.VersionInfo2 - 40, // 93: telepresence.manager.Manager.GetAgentImageFQN:output_type -> telepresence.manager.AgentImageFQN - 44, // 94: telepresence.manager.Manager.GetAgentConfig:output_type -> telepresence.manager.AgentConfigResponse - 39, // 95: telepresence.manager.Manager.GetClientConfig:output_type -> telepresence.manager.CLIConfig - 26, // 96: telepresence.manager.Manager.GetTelepresenceAPI:output_type -> telepresence.manager.TelepresenceAPIInfo - 12, // 97: telepresence.manager.Manager.ArriveAsClient:output_type -> telepresence.manager.SessionInfo - 68, // 98: telepresence.manager.Manager.ReconnectAgent:output_type -> google.protobuf.Empty - 68, // 99: telepresence.manager.Manager.ReconnectClient:output_type -> google.protobuf.Empty - 12, // 100: telepresence.manager.Manager.ArriveAsAgent:output_type -> telepresence.manager.SessionInfo - 68, // 101: telepresence.manager.Manager.Remain:output_type -> google.protobuf.Empty - 68, // 102: telepresence.manager.Manager.Depart:output_type -> google.protobuf.Empty - 68, // 103: telepresence.manager.Manager.SetLogLevel:output_type -> google.protobuf.Empty - 25, // 104: telepresence.manager.Manager.GetLogs:output_type -> telepresence.manager.LogsResponse - 42, // 105: telepresence.manager.Manager.WatchAgentPods:output_type -> telepresence.manager.AgentPodInfoSnapshot - 14, // 106: telepresence.manager.Manager.WatchAgents:output_type -> telepresence.manager.AgentInfoSnapshot - 15, // 107: telepresence.manager.Manager.WatchIntercepts:output_type -> telepresence.manager.InterceptInfoSnapshot - 49, // 108: telepresence.manager.Manager.WatchWorkloads:output_type -> telepresence.manager.WorkloadEventsDelta - 36, // 109: telepresence.manager.Manager.WatchClusterInfo:output_type -> telepresence.manager.ClusterInfo - 14, // 110: telepresence.manager.Manager.EnsureAgent:output_type -> telepresence.manager.AgentInfoSnapshot - 18, // 111: telepresence.manager.Manager.PrepareIntercept:output_type -> telepresence.manager.PreparedIntercept - 9, // 112: telepresence.manager.Manager.CreateIntercept:output_type -> telepresence.manager.InterceptInfo - 68, // 113: telepresence.manager.Manager.RemoveIntercept:output_type -> google.protobuf.Empty - 9, // 114: telepresence.manager.Manager.GetIntercept:output_type -> telepresence.manager.InterceptInfo - 68, // 115: telepresence.manager.Manager.ReviewIntercept:output_type -> google.protobuf.Empty - 46, // 116: telepresence.manager.Manager.GetKnownWorkloadKinds:output_type -> telepresence.manager.KnownWorkloadKinds - 31, // 117: telepresence.manager.Manager.Lookup:output_type -> telepresence.manager.LookupResponse - 33, // 118: telepresence.manager.Manager.LookupDNS:output_type -> telepresence.manager.DNSResponse - 23, // 119: telepresence.manager.Manager.WatchLogLevel:output_type -> telepresence.manager.LogLevelRequest - 28, // 120: telepresence.manager.Manager.Tunnel:output_type -> telepresence.manager.TunnelMessage - 68, // 121: telepresence.manager.Manager.ReportMetrics:output_type -> google.protobuf.Empty - 68, // 122: telepresence.manager.Manager.UninstallAgents:output_type -> google.protobuf.Empty - 92, // [92:123] is the sub-list for method output_type - 61, // [61:92] is the sub-list for method input_type - 61, // [61:61] is the sub-list for extension type_name - 61, // [61:61] is the sub-list for extension extendee - 0, // [0:61] is the sub-list for field type_name + 47, // 51: telepresence.manager.WorkloadInfo.ports:type_name -> telepresence.manager.WorkloadPortInfo + 4, // 52: telepresence.manager.WorkloadEvent.type:type_name -> telepresence.manager.WorkloadEvent.Type + 48, // 53: telepresence.manager.WorkloadEvent.workload:type_name -> telepresence.manager.WorkloadInfo + 67, // 54: telepresence.manager.WorkloadEventsDelta.since:type_name -> google.protobuf.Timestamp + 49, // 55: telepresence.manager.WorkloadEventsDelta.events:type_name -> telepresence.manager.WorkloadEvent + 12, // 56: telepresence.manager.WorkloadEventsRequest.session_info:type_name -> telepresence.manager.SessionInfo + 67, // 57: telepresence.manager.WorkloadEventsRequest.since:type_name -> google.protobuf.Timestamp + 12, // 58: telepresence.manager.UninstallAgentsRequest.session_info:type_name -> telepresence.manager.SessionInfo + 56, // 59: telepresence.manager.AgentInfo.ContainerInfo.environment:type_name -> telepresence.manager.AgentInfo.ContainerInfo.EnvironmentEntry + 57, // 60: telepresence.manager.AgentInfo.ContainerInfo.mounts:type_name -> telepresence.manager.AgentInfo.ContainerInfo.MountsEntry + 54, // 61: telepresence.manager.AgentInfo.ContainersEntry.value:type_name -> telepresence.manager.AgentInfo.ContainerInfo + 69, // 62: telepresence.manager.Manager.Version:input_type -> google.protobuf.Empty + 69, // 63: telepresence.manager.Manager.GetAgentImageFQN:input_type -> google.protobuf.Empty + 43, // 64: telepresence.manager.Manager.GetAgentConfig:input_type -> telepresence.manager.AgentConfigRequest + 69, // 65: telepresence.manager.Manager.GetClientConfig:input_type -> google.protobuf.Empty + 69, // 66: telepresence.manager.Manager.GetTelepresenceAPI:input_type -> google.protobuf.Empty + 5, // 67: telepresence.manager.Manager.ArriveAsClient:input_type -> telepresence.manager.ClientInfo + 10, // 68: telepresence.manager.Manager.ReconnectAgent:input_type -> telepresence.manager.ReconnectAgentRequest + 11, // 69: telepresence.manager.Manager.ReconnectClient:input_type -> telepresence.manager.ReconnectClientRequest + 6, // 70: telepresence.manager.Manager.ArriveAsAgent:input_type -> telepresence.manager.AgentInfo + 22, // 71: telepresence.manager.Manager.Remain:input_type -> telepresence.manager.RemainRequest + 12, // 72: telepresence.manager.Manager.Depart:input_type -> telepresence.manager.SessionInfo + 23, // 73: telepresence.manager.Manager.SetLogLevel:input_type -> telepresence.manager.LogLevelRequest + 24, // 74: telepresence.manager.Manager.GetLogs:input_type -> telepresence.manager.GetLogsRequest + 12, // 75: telepresence.manager.Manager.WatchAgentPods:input_type -> telepresence.manager.SessionInfo + 12, // 76: telepresence.manager.Manager.WatchAgents:input_type -> telepresence.manager.SessionInfo + 12, // 77: telepresence.manager.Manager.WatchIntercepts:input_type -> telepresence.manager.SessionInfo + 51, // 78: telepresence.manager.Manager.WatchWorkloads:input_type -> telepresence.manager.WorkloadEventsRequest + 12, // 79: telepresence.manager.Manager.WatchClusterInfo:input_type -> telepresence.manager.SessionInfo + 17, // 80: telepresence.manager.Manager.EnsureAgent:input_type -> telepresence.manager.EnsureAgentRequest + 16, // 81: telepresence.manager.Manager.PrepareIntercept:input_type -> telepresence.manager.CreateInterceptRequest + 16, // 82: telepresence.manager.Manager.CreateIntercept:input_type -> telepresence.manager.CreateInterceptRequest + 19, // 83: telepresence.manager.Manager.RemoveIntercept:input_type -> telepresence.manager.RemoveInterceptRequest2 + 20, // 84: telepresence.manager.Manager.GetIntercept:input_type -> telepresence.manager.GetInterceptRequest + 21, // 85: telepresence.manager.Manager.ReviewIntercept:input_type -> telepresence.manager.ReviewInterceptRequest + 12, // 86: telepresence.manager.Manager.GetKnownWorkloadKinds:input_type -> telepresence.manager.SessionInfo + 30, // 87: telepresence.manager.Manager.Lookup:input_type -> telepresence.manager.LookupRequest + 32, // 88: telepresence.manager.Manager.LookupDNS:input_type -> telepresence.manager.DNSRequest + 69, // 89: telepresence.manager.Manager.WatchLogLevel:input_type -> google.protobuf.Empty + 28, // 90: telepresence.manager.Manager.Tunnel:input_type -> telepresence.manager.TunnelMessage + 45, // 91: telepresence.manager.Manager.ReportMetrics:input_type -> telepresence.manager.TunnelMetrics + 52, // 92: telepresence.manager.Manager.UninstallAgents:input_type -> telepresence.manager.UninstallAgentsRequest + 27, // 93: telepresence.manager.Manager.Version:output_type -> telepresence.manager.VersionInfo2 + 40, // 94: telepresence.manager.Manager.GetAgentImageFQN:output_type -> telepresence.manager.AgentImageFQN + 44, // 95: telepresence.manager.Manager.GetAgentConfig:output_type -> telepresence.manager.AgentConfigResponse + 39, // 96: telepresence.manager.Manager.GetClientConfig:output_type -> telepresence.manager.CLIConfig + 26, // 97: telepresence.manager.Manager.GetTelepresenceAPI:output_type -> telepresence.manager.TelepresenceAPIInfo + 12, // 98: telepresence.manager.Manager.ArriveAsClient:output_type -> telepresence.manager.SessionInfo + 69, // 99: telepresence.manager.Manager.ReconnectAgent:output_type -> google.protobuf.Empty + 69, // 100: telepresence.manager.Manager.ReconnectClient:output_type -> google.protobuf.Empty + 12, // 101: telepresence.manager.Manager.ArriveAsAgent:output_type -> telepresence.manager.SessionInfo + 69, // 102: telepresence.manager.Manager.Remain:output_type -> google.protobuf.Empty + 69, // 103: telepresence.manager.Manager.Depart:output_type -> google.protobuf.Empty + 69, // 104: telepresence.manager.Manager.SetLogLevel:output_type -> google.protobuf.Empty + 25, // 105: telepresence.manager.Manager.GetLogs:output_type -> telepresence.manager.LogsResponse + 42, // 106: telepresence.manager.Manager.WatchAgentPods:output_type -> telepresence.manager.AgentPodInfoSnapshot + 14, // 107: telepresence.manager.Manager.WatchAgents:output_type -> telepresence.manager.AgentInfoSnapshot + 15, // 108: telepresence.manager.Manager.WatchIntercepts:output_type -> telepresence.manager.InterceptInfoSnapshot + 50, // 109: telepresence.manager.Manager.WatchWorkloads:output_type -> telepresence.manager.WorkloadEventsDelta + 36, // 110: telepresence.manager.Manager.WatchClusterInfo:output_type -> telepresence.manager.ClusterInfo + 14, // 111: telepresence.manager.Manager.EnsureAgent:output_type -> telepresence.manager.AgentInfoSnapshot + 18, // 112: telepresence.manager.Manager.PrepareIntercept:output_type -> telepresence.manager.PreparedIntercept + 9, // 113: telepresence.manager.Manager.CreateIntercept:output_type -> telepresence.manager.InterceptInfo + 69, // 114: telepresence.manager.Manager.RemoveIntercept:output_type -> google.protobuf.Empty + 9, // 115: telepresence.manager.Manager.GetIntercept:output_type -> telepresence.manager.InterceptInfo + 69, // 116: telepresence.manager.Manager.ReviewIntercept:output_type -> google.protobuf.Empty + 46, // 117: telepresence.manager.Manager.GetKnownWorkloadKinds:output_type -> telepresence.manager.KnownWorkloadKinds + 31, // 118: telepresence.manager.Manager.Lookup:output_type -> telepresence.manager.LookupResponse + 33, // 119: telepresence.manager.Manager.LookupDNS:output_type -> telepresence.manager.DNSResponse + 23, // 120: telepresence.manager.Manager.WatchLogLevel:output_type -> telepresence.manager.LogLevelRequest + 28, // 121: telepresence.manager.Manager.Tunnel:output_type -> telepresence.manager.TunnelMessage + 69, // 122: telepresence.manager.Manager.ReportMetrics:output_type -> google.protobuf.Empty + 69, // 123: telepresence.manager.Manager.UninstallAgents:output_type -> google.protobuf.Empty + 93, // [93:124] is the sub-list for method output_type + 62, // [62:93] is the sub-list for method input_type + 62, // [62:62] is the sub-list for extension type_name + 62, // [62:62] is the sub-list for extension extendee + 0, // [0:62] is the sub-list for field type_name } func init() { file_manager_manager_proto_init() } @@ -4472,7 +4572,7 @@ func file_manager_manager_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_manager_manager_proto_rawDesc), len(file_manager_manager_proto_rawDesc)), NumEnums: 5, - NumMessages: 61, + NumMessages: 62, NumExtensions: 0, NumServices: 1, }, diff --git a/rpc/manager/manager.proto b/rpc/manager/manager.proto index ce4097e4d6..d2d133ee36 100644 --- a/rpc/manager/manager.proto +++ b/rpc/manager/manager.proto @@ -606,6 +606,24 @@ message KnownWorkloadKinds { repeated WorkloadInfo.Kind kinds = 1; } +// WorkloadPortInfo describes a port exposed by a workload's container +message WorkloadPortInfo { + // Symbolic name of the container port (e.g., "http", "grpc") + string container_port_name = 1; + + // Numeric container port number (mandatory, always present) + int32 container_port = 2; + + // Protocol used by the port (TCP or UDP) + string protocol = 3; + + // Symbolic name of the service port (may be empty for headless services or replacements) + string service_port_name = 4; + + // Numeric service port number (may be 0 for headless services or replacements) + int32 service_port = 5; +} + // WorkloadInfo contains information about a workload (typically a // Deployment). message WorkloadInfo { @@ -660,6 +678,9 @@ message WorkloadInfo { repeated Intercept intercept_clients = 5; State state = 6; + + // Ports exposed by containers in this workload + repeated WorkloadPortInfo ports = 8; } message WorkloadEvent {