mirror of
https://github.com/lukaszraczylo/kportal.git
synced 2026-06-05 23:03:40 +00:00
Add aliases and conversion from the kftray.
This commit is contained in:
@@ -12,12 +12,14 @@ contexts:
|
||||
protocol: tcp
|
||||
port: 8080
|
||||
localPort: 8080
|
||||
alias: prod-api
|
||||
|
||||
# Forward to PostgreSQL database
|
||||
- resource: service/postgres
|
||||
protocol: tcp
|
||||
port: 5432
|
||||
localPort: 5432
|
||||
alias: prod-db
|
||||
|
||||
- name: monitoring
|
||||
forwards:
|
||||
@@ -27,6 +29,7 @@ contexts:
|
||||
protocol: tcp
|
||||
port: 9090
|
||||
localPort: 9090
|
||||
alias: prometheus
|
||||
|
||||
# Staging context
|
||||
- name: staging
|
||||
@@ -38,9 +41,11 @@ contexts:
|
||||
protocol: tcp
|
||||
port: 8080
|
||||
localPort: 8081
|
||||
alias: staging-http
|
||||
|
||||
# Forward multiple ports from same pod
|
||||
- resource: pod/myapp
|
||||
protocol: tcp
|
||||
port: 9090
|
||||
localPort: 9091
|
||||
alias: staging-metrics
|
||||
|
||||
@@ -48,6 +48,9 @@ go build -o kportal ./cmd/kportal
|
||||
|
||||
# Validate configuration without starting
|
||||
./kportal --check
|
||||
|
||||
# Convert kftray JSON config to kportal YAML
|
||||
./kportal --convert configs.json --convert-output .kportal.yaml
|
||||
```
|
||||
|
||||
### Configuration File
|
||||
@@ -65,12 +68,14 @@ contexts:
|
||||
protocol: tcp
|
||||
port: 8080
|
||||
localPort: 8080
|
||||
alias: my-api # Optional: cleaner log output
|
||||
|
||||
# Service forwarding
|
||||
# Service forwarding with alias
|
||||
- resource: service/postgres
|
||||
protocol: tcp
|
||||
port: 5432
|
||||
localPort: 5432
|
||||
alias: prod-db
|
||||
|
||||
- name: monitoring
|
||||
forwards:
|
||||
@@ -80,6 +85,7 @@ contexts:
|
||||
protocol: tcp
|
||||
port: 9090
|
||||
localPort: 9090
|
||||
alias: prometheus
|
||||
|
||||
- name: staging
|
||||
namespaces:
|
||||
@@ -89,10 +95,12 @@ contexts:
|
||||
- resource: pod/test-app
|
||||
port: 8080
|
||||
localPort: 8081
|
||||
alias: test-http
|
||||
|
||||
- resource: pod/test-app
|
||||
port: 9090
|
||||
localPort: 9091
|
||||
alias: test-metrics
|
||||
```
|
||||
|
||||
### Resource Types
|
||||
@@ -122,6 +130,72 @@ Dynamically selects pods matching the label selector.
|
||||
```
|
||||
Most stable option - forwards to service endpoints.
|
||||
|
||||
#### Using Aliases
|
||||
|
||||
Aliases provide cleaner, more readable log output:
|
||||
|
||||
```yaml
|
||||
- resource: service/victoria-metrics-cluster-vmselect
|
||||
port: 8481
|
||||
localPort: 8481
|
||||
alias: vmetrics # Shows "vmetrics:8481→8481" instead of full path
|
||||
```
|
||||
|
||||
**Without alias:**
|
||||
```
|
||||
[home/monitoring/service/victoria-metrics-cluster-vmselect:8481] Forwarding...
|
||||
```
|
||||
|
||||
**With alias:**
|
||||
```
|
||||
[vmetrics:8481] Forwarding vmetrics:8481→8481 → localhost:8481
|
||||
```
|
||||
|
||||
### Converting from kftray
|
||||
|
||||
kportal can automatically convert kftray JSON configurations to kportal YAML format:
|
||||
|
||||
```bash
|
||||
# Convert kftray config
|
||||
kportal --convert kftray-config.json --convert-output .kportal.yaml
|
||||
|
||||
# The converter will:
|
||||
# 1. Read the kftray JSON format
|
||||
# 2. Group forwards by context and namespace
|
||||
# 3. Generate kportal YAML with all aliases preserved
|
||||
# 4. Display a summary of the conversion
|
||||
```
|
||||
|
||||
**Example kftray JSON:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"service": "postgres",
|
||||
"namespace": "default",
|
||||
"local_port": 5432,
|
||||
"remote_port": 5432,
|
||||
"context": "production",
|
||||
"workload_type": "service",
|
||||
"protocol": "tcp",
|
||||
"alias": "prod-db"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Converts to kportal YAML:**
|
||||
```yaml
|
||||
contexts:
|
||||
- name: production
|
||||
namespaces:
|
||||
- name: default
|
||||
forwards:
|
||||
- resource: service/postgres
|
||||
protocol: tcp
|
||||
port: 5432
|
||||
localPort: 5432
|
||||
alias: prod-db
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
### Pod Restart Handling
|
||||
|
||||
@@ -26,11 +26,12 @@ type Namespace struct {
|
||||
|
||||
// Forward represents a single port-forward configuration
|
||||
type Forward struct {
|
||||
Resource string `yaml:"resource"` // e.g., "pod/my-app", "service/postgres", "pod"
|
||||
Selector string `yaml:"selector"` // Label selector for pod resolution (e.g., "app=nginx,env=prod")
|
||||
Protocol string `yaml:"protocol"` // tcp or udp
|
||||
Port int `yaml:"port"` // Remote port
|
||||
LocalPort int `yaml:"localPort"` // Local port
|
||||
Resource string `yaml:"resource"` // e.g., "pod/my-app", "service/postgres", "pod"
|
||||
Selector string `yaml:"selector"` // Label selector for pod resolution (e.g., "app=nginx,env=prod")
|
||||
Protocol string `yaml:"protocol"` // tcp or udp
|
||||
Port int `yaml:"port"` // Remote port
|
||||
LocalPort int `yaml:"localPort"` // Local port
|
||||
Alias string `yaml:"alias,omitempty"` // Optional human-readable alias for this forward
|
||||
|
||||
// Runtime fields (not in YAML)
|
||||
contextName string
|
||||
@@ -38,14 +39,20 @@ type Forward struct {
|
||||
}
|
||||
|
||||
// ID returns a unique identifier for this forward configuration.
|
||||
// Format: context/namespace/resource:localPort
|
||||
// Format: alias:localPort (if alias provided) or context/namespace/resource:localPort
|
||||
func (f *Forward) ID() string {
|
||||
if f.Alias != "" {
|
||||
return fmt.Sprintf("%s:%d", f.Alias, f.LocalPort)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s/%s:%d", f.contextName, f.namespaceName, f.Resource, f.LocalPort)
|
||||
}
|
||||
|
||||
// String returns a human-readable representation of the forward.
|
||||
// Format: context/namespace/resource:port→localPort
|
||||
// Format: alias:port→localPort (if alias provided) or context/namespace/resource:port→localPort
|
||||
func (f *Forward) String() string {
|
||||
if f.Alias != "" {
|
||||
return fmt.Sprintf("%s:%d→%d", f.Alias, f.Port, f.LocalPort)
|
||||
}
|
||||
if f.Selector != "" {
|
||||
return fmt.Sprintf("%s/%s/%s[%s]:%d→%d",
|
||||
f.contextName, f.namespaceName, f.Resource, f.Selector, f.Port, f.LocalPort)
|
||||
|
||||
@@ -140,6 +140,18 @@ func TestForward_ID(t *testing.T) {
|
||||
},
|
||||
expectedID: "staging/web/pod:8081",
|
||||
},
|
||||
{
|
||||
name: "forward with alias",
|
||||
forward: Forward{
|
||||
Resource: "service/postgres",
|
||||
Port: 5432,
|
||||
LocalPort: 5432,
|
||||
Alias: "shared-postgres",
|
||||
contextName: "home",
|
||||
namespaceName: "shared-resources",
|
||||
},
|
||||
expectedID: "shared-postgres:5432",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
@@ -190,6 +202,18 @@ func TestForward_String(t *testing.T) {
|
||||
},
|
||||
expectedString: "staging/web/pod[app=nginx,env=prod]:80→8081",
|
||||
},
|
||||
{
|
||||
name: "forward with alias",
|
||||
forward: Forward{
|
||||
Resource: "service/redis",
|
||||
Port: 6379,
|
||||
LocalPort: 6379,
|
||||
Alias: "redis-at-home",
|
||||
contextName: "home",
|
||||
namespaceName: "shared-resources",
|
||||
},
|
||||
expectedString: "redis-at-home:6379→6379",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
package converter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/nvm/kportal/internal/config"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// KFTrayConfig represents a single port-forward entry from kftray JSON format
|
||||
type KFTrayConfig struct {
|
||||
Service string `json:"service"`
|
||||
Namespace string `json:"namespace"`
|
||||
LocalPort int `json:"local_port"`
|
||||
RemotePort int `json:"remote_port"`
|
||||
Context string `json:"context"`
|
||||
WorkloadType string `json:"workload_type"`
|
||||
Protocol string `json:"protocol"`
|
||||
Alias string `json:"alias"`
|
||||
}
|
||||
|
||||
// ConvertKFTrayToKPortal converts kftray JSON configuration to kportal YAML format
|
||||
func ConvertKFTrayToKPortal(inputFile, outputFile string) error {
|
||||
// Read kftray JSON config
|
||||
data, err := os.ReadFile(inputFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read input file: %w", err)
|
||||
}
|
||||
|
||||
var kftrayConfigs []KFTrayConfig
|
||||
if err := json.Unmarshal(data, &kftrayConfigs); err != nil {
|
||||
return fmt.Errorf("failed to parse JSON: %w", err)
|
||||
}
|
||||
|
||||
// Convert to kportal format
|
||||
kportalConfig := convertToKPortal(kftrayConfigs)
|
||||
|
||||
// Write kportal YAML config
|
||||
yamlData, err := yaml.Marshal(kportalConfig)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to generate YAML: %w", err)
|
||||
}
|
||||
|
||||
// Add header comment
|
||||
header := "# kportal configuration converted from kftray format\n# Generated by kportal --convert\n\n"
|
||||
yamlData = append([]byte(header), yamlData...)
|
||||
|
||||
if err := os.WriteFile(outputFile, yamlData, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write output file: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetConversionSummary returns statistics about the kftray configuration
|
||||
func GetConversionSummary(inputFile string) (map[string]map[string]int, int, error) {
|
||||
data, err := os.ReadFile(inputFile)
|
||||
if err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to read input file: %w", err)
|
||||
}
|
||||
|
||||
var kftrayConfigs []KFTrayConfig
|
||||
if err := json.Unmarshal(data, &kftrayConfigs); err != nil {
|
||||
return nil, 0, fmt.Errorf("failed to parse JSON: %w", err)
|
||||
}
|
||||
|
||||
contextMap := make(map[string]map[string]int)
|
||||
for _, cfg := range kftrayConfigs {
|
||||
if _, ok := contextMap[cfg.Context]; !ok {
|
||||
contextMap[cfg.Context] = make(map[string]int)
|
||||
}
|
||||
contextMap[cfg.Context][cfg.Namespace]++
|
||||
}
|
||||
|
||||
return contextMap, len(kftrayConfigs), nil
|
||||
}
|
||||
|
||||
func convertToKPortal(kftrayConfigs []KFTrayConfig) config.Config {
|
||||
// Group by context and namespace
|
||||
contextMap := make(map[string]map[string][]forwardEntry)
|
||||
|
||||
for _, cfg := range kftrayConfigs {
|
||||
// Initialize context if not exists
|
||||
if _, ok := contextMap[cfg.Context]; !ok {
|
||||
contextMap[cfg.Context] = make(map[string][]forwardEntry)
|
||||
}
|
||||
|
||||
// Build resource string based on workload type
|
||||
resource := fmt.Sprintf("%s/%s", cfg.WorkloadType, cfg.Service)
|
||||
|
||||
// Create forward entry
|
||||
forward := forwardEntry{
|
||||
Resource: resource,
|
||||
Protocol: cfg.Protocol,
|
||||
Port: cfg.RemotePort,
|
||||
LocalPort: cfg.LocalPort,
|
||||
Alias: cfg.Alias,
|
||||
}
|
||||
|
||||
// Add to namespace
|
||||
contextMap[cfg.Context][cfg.Namespace] = append(
|
||||
contextMap[cfg.Context][cfg.Namespace],
|
||||
forward,
|
||||
)
|
||||
}
|
||||
|
||||
// Convert map to structured config
|
||||
var contexts []contextEntry
|
||||
|
||||
// Sort contexts for consistent output
|
||||
contextNames := make([]string, 0, len(contextMap))
|
||||
for name := range contextMap {
|
||||
contextNames = append(contextNames, name)
|
||||
}
|
||||
sort.Strings(contextNames)
|
||||
|
||||
for _, contextName := range contextNames {
|
||||
namespaceMap := contextMap[contextName]
|
||||
|
||||
// Sort namespaces
|
||||
namespaceNames := make([]string, 0, len(namespaceMap))
|
||||
for name := range namespaceMap {
|
||||
namespaceNames = append(namespaceNames, name)
|
||||
}
|
||||
sort.Strings(namespaceNames)
|
||||
|
||||
var namespaces []namespaceEntry
|
||||
for _, namespaceName := range namespaceNames {
|
||||
forwards := namespaceMap[namespaceName]
|
||||
|
||||
// Sort forwards by local port for consistent output
|
||||
sort.Slice(forwards, func(i, j int) bool {
|
||||
return forwards[i].LocalPort < forwards[j].LocalPort
|
||||
})
|
||||
|
||||
namespaces = append(namespaces, namespaceEntry{
|
||||
Name: namespaceName,
|
||||
Forwards: forwards,
|
||||
})
|
||||
}
|
||||
|
||||
contexts = append(contexts, contextEntry{
|
||||
Name: contextName,
|
||||
Namespaces: namespaces,
|
||||
})
|
||||
}
|
||||
|
||||
return config.Config{
|
||||
Contexts: convertToConfigContexts(contexts),
|
||||
}
|
||||
}
|
||||
|
||||
// Internal types for conversion (to avoid circular dependencies)
|
||||
type contextEntry struct {
|
||||
Name string
|
||||
Namespaces []namespaceEntry
|
||||
}
|
||||
|
||||
type namespaceEntry struct {
|
||||
Name string
|
||||
Forwards []forwardEntry
|
||||
}
|
||||
|
||||
type forwardEntry struct {
|
||||
Resource string `yaml:"resource"`
|
||||
Protocol string `yaml:"protocol"`
|
||||
Port int `yaml:"port"`
|
||||
LocalPort int `yaml:"localPort"`
|
||||
Alias string `yaml:"alias,omitempty"`
|
||||
}
|
||||
|
||||
// Convert internal types to config package types
|
||||
func convertToConfigContexts(contexts []contextEntry) []config.Context {
|
||||
var result []config.Context
|
||||
for _, ctx := range contexts {
|
||||
var namespaces []config.Namespace
|
||||
for _, ns := range ctx.Namespaces {
|
||||
var forwards []config.Forward
|
||||
for _, fwd := range ns.Forwards {
|
||||
forwards = append(forwards, config.Forward{
|
||||
Resource: fwd.Resource,
|
||||
Protocol: fwd.Protocol,
|
||||
Port: fwd.Port,
|
||||
LocalPort: fwd.LocalPort,
|
||||
Alias: fwd.Alias,
|
||||
})
|
||||
}
|
||||
namespaces = append(namespaces, config.Namespace{
|
||||
Name: ns.Name,
|
||||
Forwards: forwards,
|
||||
})
|
||||
}
|
||||
result = append(result, config.Context{
|
||||
Name: ctx.Name,
|
||||
Namespaces: namespaces,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
package converter
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestConvertToKPortal_SingleContext(t *testing.T) {
|
||||
kftrayConfigs := []KFTrayConfig{
|
||||
{
|
||||
Service: "postgres",
|
||||
Namespace: "default",
|
||||
LocalPort: 5432,
|
||||
RemotePort: 5432,
|
||||
Context: "production",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "prod-db",
|
||||
},
|
||||
}
|
||||
|
||||
result := convertToKPortal(kftrayConfigs)
|
||||
|
||||
assert.Len(t, result.Contexts, 1)
|
||||
assert.Equal(t, "production", result.Contexts[0].Name)
|
||||
assert.Len(t, result.Contexts[0].Namespaces, 1)
|
||||
assert.Equal(t, "default", result.Contexts[0].Namespaces[0].Name)
|
||||
assert.Len(t, result.Contexts[0].Namespaces[0].Forwards, 1)
|
||||
|
||||
forward := result.Contexts[0].Namespaces[0].Forwards[0]
|
||||
assert.Equal(t, "service/postgres", forward.Resource)
|
||||
assert.Equal(t, "tcp", forward.Protocol)
|
||||
assert.Equal(t, 5432, forward.Port)
|
||||
assert.Equal(t, 5432, forward.LocalPort)
|
||||
assert.Equal(t, "prod-db", forward.Alias)
|
||||
}
|
||||
|
||||
func TestConvertToKPortal_MultipleContexts(t *testing.T) {
|
||||
kftrayConfigs := []KFTrayConfig{
|
||||
{
|
||||
Service: "api",
|
||||
Namespace: "default",
|
||||
LocalPort: 8080,
|
||||
RemotePort: 8080,
|
||||
Context: "production",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "prod-api",
|
||||
},
|
||||
{
|
||||
Service: "api",
|
||||
Namespace: "default",
|
||||
LocalPort: 8081,
|
||||
RemotePort: 8080,
|
||||
Context: "staging",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "staging-api",
|
||||
},
|
||||
}
|
||||
|
||||
result := convertToKPortal(kftrayConfigs)
|
||||
|
||||
assert.Len(t, result.Contexts, 2)
|
||||
|
||||
// Contexts should be sorted alphabetically
|
||||
assert.Equal(t, "production", result.Contexts[0].Name)
|
||||
assert.Equal(t, "staging", result.Contexts[1].Name)
|
||||
}
|
||||
|
||||
func TestConvertToKPortal_MultipleNamespaces(t *testing.T) {
|
||||
kftrayConfigs := []KFTrayConfig{
|
||||
{
|
||||
Service: "api",
|
||||
Namespace: "default",
|
||||
LocalPort: 8080,
|
||||
RemotePort: 8080,
|
||||
Context: "production",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "api",
|
||||
},
|
||||
{
|
||||
Service: "postgres",
|
||||
Namespace: "database",
|
||||
LocalPort: 5432,
|
||||
RemotePort: 5432,
|
||||
Context: "production",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "db",
|
||||
},
|
||||
}
|
||||
|
||||
result := convertToKPortal(kftrayConfigs)
|
||||
|
||||
assert.Len(t, result.Contexts, 1)
|
||||
assert.Len(t, result.Contexts[0].Namespaces, 2)
|
||||
|
||||
// Namespaces should be sorted alphabetically
|
||||
assert.Equal(t, "database", result.Contexts[0].Namespaces[0].Name)
|
||||
assert.Equal(t, "default", result.Contexts[0].Namespaces[1].Name)
|
||||
}
|
||||
|
||||
func TestConvertToKPortal_MultipleForwardsInNamespace(t *testing.T) {
|
||||
kftrayConfigs := []KFTrayConfig{
|
||||
{
|
||||
Service: "api",
|
||||
Namespace: "default",
|
||||
LocalPort: 8080,
|
||||
RemotePort: 8080,
|
||||
Context: "production",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "api",
|
||||
},
|
||||
{
|
||||
Service: "postgres",
|
||||
Namespace: "default",
|
||||
LocalPort: 5432,
|
||||
RemotePort: 5432,
|
||||
Context: "production",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "db",
|
||||
},
|
||||
{
|
||||
Service: "redis",
|
||||
Namespace: "default",
|
||||
LocalPort: 6379,
|
||||
RemotePort: 6379,
|
||||
Context: "production",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "redis",
|
||||
},
|
||||
}
|
||||
|
||||
result := convertToKPortal(kftrayConfigs)
|
||||
|
||||
assert.Len(t, result.Contexts, 1)
|
||||
assert.Len(t, result.Contexts[0].Namespaces, 1)
|
||||
assert.Len(t, result.Contexts[0].Namespaces[0].Forwards, 3)
|
||||
|
||||
// Forwards should be sorted by local port
|
||||
forwards := result.Contexts[0].Namespaces[0].Forwards
|
||||
assert.Equal(t, 5432, forwards[0].LocalPort) // postgres
|
||||
assert.Equal(t, 6379, forwards[1].LocalPort) // redis
|
||||
assert.Equal(t, 8080, forwards[2].LocalPort) // api
|
||||
}
|
||||
|
||||
func TestConvertToKPortal_PodWorkloadType(t *testing.T) {
|
||||
kftrayConfigs := []KFTrayConfig{
|
||||
{
|
||||
Service: "my-app",
|
||||
Namespace: "default",
|
||||
LocalPort: 8080,
|
||||
RemotePort: 8080,
|
||||
Context: "production",
|
||||
WorkloadType: "pod",
|
||||
Protocol: "tcp",
|
||||
Alias: "app",
|
||||
},
|
||||
}
|
||||
|
||||
result := convertToKPortal(kftrayConfigs)
|
||||
|
||||
forward := result.Contexts[0].Namespaces[0].Forwards[0]
|
||||
assert.Equal(t, "pod/my-app", forward.Resource)
|
||||
}
|
||||
|
||||
func TestConvertToKPortal_WithoutAlias(t *testing.T) {
|
||||
kftrayConfigs := []KFTrayConfig{
|
||||
{
|
||||
Service: "postgres",
|
||||
Namespace: "default",
|
||||
LocalPort: 5432,
|
||||
RemotePort: 5432,
|
||||
Context: "production",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "", // No alias
|
||||
},
|
||||
}
|
||||
|
||||
result := convertToKPortal(kftrayConfigs)
|
||||
|
||||
forward := result.Contexts[0].Namespaces[0].Forwards[0]
|
||||
assert.Equal(t, "", forward.Alias)
|
||||
}
|
||||
|
||||
func TestConvertToKPortal_DifferentPorts(t *testing.T) {
|
||||
kftrayConfigs := []KFTrayConfig{
|
||||
{
|
||||
Service: "api",
|
||||
Namespace: "default",
|
||||
LocalPort: 8080,
|
||||
RemotePort: 3000,
|
||||
Context: "production",
|
||||
WorkloadType: "service",
|
||||
Protocol: "tcp",
|
||||
Alias: "api",
|
||||
},
|
||||
}
|
||||
|
||||
result := convertToKPortal(kftrayConfigs)
|
||||
|
||||
forward := result.Contexts[0].Namespaces[0].Forwards[0]
|
||||
assert.Equal(t, 3000, forward.Port, "Remote port should be 3000")
|
||||
assert.Equal(t, 8080, forward.LocalPort, "Local port should be 8080")
|
||||
}
|
||||
Reference in New Issue
Block a user