Skip to content

Commit 34781cd

Browse files
authored
Merge pull request #87 from Eeshu-Yadav/feat/internal-listener-upstream-transport_1
feat: add internal listener and upstream transport support
2 parents b8e1f63 + 24e988f commit 34781cd

File tree

31 files changed

+2071
-356
lines changed

31 files changed

+2071
-356
lines changed

Cargo.lock

Lines changed: 186 additions & 158 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Internal Listener and Upstream Transport Demo
2+
3+
This demo demonstrates Orion's internal listener and upstream transport functionality for service mesh communication.
4+
5+
## Quick Test
6+
7+
```bash
8+
./test_internal_config.sh
9+
```
10+
11+
## Configuration
12+
13+
### Internal Listener
14+
15+
```yaml
16+
listeners:
17+
- name: internal_mesh_listener
18+
address:
19+
internal:
20+
buffer_size_kb: 1024
21+
filter_chains:
22+
- name: internal_proxy_chain
23+
terminal_filter:
24+
tcp_proxy:
25+
cluster: internal_backend_cluster
26+
```
27+
28+
### Internal Endpoints
29+
30+
```yaml
31+
clusters:
32+
- name: internal_service_cluster
33+
type: STATIC
34+
load_assignment:
35+
endpoints:
36+
- lb_endpoints:
37+
- endpoint:
38+
address:
39+
internal:
40+
server_listener_name: internal_mesh_listener
41+
endpoint_id: service_a_endpoint_1
42+
```
43+
44+
### Internal Upstream Transport
45+
46+
```yaml
47+
transport_socket:
48+
internal_upstream:
49+
passthrough_metadata:
50+
- kind: HOST
51+
name: envoy.filters.listener.original_dst
52+
transport_socket:
53+
raw_buffer: {}
54+
```
55+
56+
### Bootstrap Extensions
57+
58+
```yaml
59+
bootstrap_extensions:
60+
- internal_listener:
61+
buffer_size_kb: 2048
62+
```
63+
64+
## Usage
65+
66+
```bash
67+
# Start Orion
68+
../../target/debug/orion -c orion-config.yaml
69+
70+
# Test endpoints
71+
curl http://localhost:10000/
72+
curl http://localhost:10000/service-a
73+
74+
# Monitor
75+
curl http://localhost:9901/stats
76+
```
77+
78+
## Features
79+
80+
- Internal listeners for service mesh communication
81+
- Internal endpoints with server_listener_name references
82+
- Metadata passthrough via internal upstream transport
83+
- Global bootstrap extensions configuration
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
// Copyright 2025 The kmesh Authors
2+
//
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
//
17+
18+
use std::env;
19+
use std::io::{Read, Write};
20+
use std::net::{TcpStream, ToSocketAddrs};
21+
use std::time::Duration;
22+
23+
fn main() {
24+
let args: Vec<String> = env::args().collect();
25+
26+
if args.len() < 2 {
27+
println!("Usage: {} <test_type>", args[0]);
28+
println!("Test types: gateway, admin, health");
29+
return;
30+
}
31+
32+
match args[1].as_str() {
33+
"gateway" => test_gateway(),
34+
"admin" => test_admin(),
35+
"health" => test_health(),
36+
_ => println!("Invalid test type. Use: gateway, admin, health"),
37+
}
38+
}
39+
40+
fn test_gateway() {
41+
println!("Testing External Gateway");
42+
43+
let endpoints = vec![
44+
("localhost:10000", "/", "Main Gateway"),
45+
("localhost:10000", "/service-a", "Service A"),
46+
];
47+
48+
for (address, path, description) in endpoints {
49+
println!("Testing {}: http://{}{}", description, address, path);
50+
match test_http_endpoint(address, path) {
51+
Ok(response) => println!(" ✅ {}", response.trim()),
52+
Err(e) => println!(" ❌ {}", e),
53+
}
54+
}
55+
}
56+
57+
fn test_admin() {
58+
println!("Testing Admin Interface");
59+
60+
let endpoints = vec![
61+
("localhost:9901", "/stats", "Statistics"),
62+
("localhost:9901", "/listeners", "Listeners"),
63+
("localhost:9901", "/clusters", "Clusters"),
64+
];
65+
66+
for (address, path, description) in endpoints {
67+
println!("Testing {}: http://{}{}", description, address, path);
68+
match test_http_endpoint(address, path) {
69+
Ok(response) => {
70+
println!(" ✅ {} lines received", response.lines().count());
71+
for line in response.lines().take(2) {
72+
if !line.trim().is_empty() {
73+
println!(" {}", line.trim());
74+
}
75+
}
76+
}
77+
Err(e) => println!(" ❌ {}", e),
78+
}
79+
}
80+
}
81+
82+
fn test_health() {
83+
println!("Testing Health Metrics");
84+
85+
match test_http_endpoint("localhost:9901", "/stats") {
86+
Ok(response) => {
87+
let internal_stats: Vec<&str> = response
88+
.lines()
89+
.filter(|line| line.contains("internal") || line.contains("listener"))
90+
.take(5)
91+
.collect();
92+
93+
if internal_stats.is_empty() {
94+
println!(" ⚠️ No internal listener stats found");
95+
} else {
96+
for stat in internal_stats {
97+
println!(" 📊 {}", stat.trim());
98+
}
99+
}
100+
}
101+
Err(e) => println!(" ❌ {}", e),
102+
}
103+
}
104+
105+
fn test_http_endpoint(address: &str, path: &str) -> Result<String, String> {
106+
let addr = address.to_socket_addrs()
107+
.map_err(|e| format!("Failed to resolve {}: {}", address, e))?
108+
.next()
109+
.ok_or_else(|| format!("No addresses found for {}", address))?;
110+
111+
let mut stream = TcpStream::connect_timeout(&addr, Duration::from_secs(5))
112+
.map_err(|e| format!("Connection failed: {}", e))?;
113+
114+
let request = format!(
115+
"GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n",
116+
path, address.split(':').next().unwrap_or("localhost")
117+
);
118+
119+
stream.write_all(request.as_bytes())
120+
.map_err(|e| format!("Failed to send request: {}", e))?;
121+
122+
let mut response = String::new();
123+
stream.read_to_string(&mut response)
124+
.map_err(|e| format!("Failed to read response: {}", e))?;
125+
126+
if let Some(body_start) = response.find("\r\n\r\n") {
127+
let (headers, body) = response.split_at(body_start + 4);
128+
129+
if headers.contains("200 OK") {
130+
Ok(body.to_string())
131+
} else if headers.contains("404") {
132+
Err("Endpoint not found (404)".to_string())
133+
} else {
134+
Err(format!("HTTP error: {}", headers.lines().next().unwrap_or("Unknown")))
135+
}
136+
} else {
137+
Err("Invalid HTTP response".to_string())
138+
}
139+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
runtime:
2+
num_cpus: 1
3+
num_runtimes: 1
4+
5+
logging:
6+
log_level: "debug"
7+
8+
bootstrap_extensions:
9+
- internal_listener:
10+
buffer_size_kb: 2048
11+
12+
admin:
13+
address: "127.0.0.1:9901"
14+
15+
static_resources:
16+
listeners:
17+
- name: "external_gateway_listener"
18+
address: "0.0.0.0:10000"
19+
filter_chains:
20+
- name: "gateway_filter_chain"
21+
terminal_filter:
22+
http_connection_manager:
23+
route_config:
24+
name: "gateway_route"
25+
virtual_hosts:
26+
- name: "services"
27+
domains: ["*"]
28+
routes:
29+
- match:
30+
prefix: "/service-a"
31+
route:
32+
cluster: "internal_service_a_cluster"
33+
- match:
34+
prefix: "/"
35+
direct_response:
36+
status: 200
37+
body: "Internal Listener Demo Active"
38+
39+
- name: "internal_mesh_listener"
40+
address:
41+
internal:
42+
buffer_size_kb: 1024
43+
filter_chains:
44+
- name: "internal_proxy_chain"
45+
terminal_filter:
46+
tcp_proxy:
47+
cluster: "internal_backend_cluster"
48+
49+
clusters:
50+
- name: "internal_service_a_cluster"
51+
type: STATIC
52+
transport_socket:
53+
internal_upstream:
54+
passthrough_metadata:
55+
- kind: HOST
56+
name: "envoy.filters.listener.original_dst"
57+
transport_socket:
58+
raw_buffer: {}
59+
load_assignment:
60+
endpoints:
61+
- lb_endpoints:
62+
- endpoint:
63+
address:
64+
internal:
65+
server_listener_name: "internal_mesh_listener"
66+
endpoint_id: "service_a_endpoint_1"
67+
68+
- name: "internal_backend_cluster"
69+
type: STATIC
70+
load_assignment:
71+
endpoints:
72+
- lb_endpoints:
73+
- endpoint:
74+
address: "127.0.0.1:8080"

0 commit comments

Comments
 (0)