Skip to content

Commit 4f476c6

Browse files
committed
feat: remove OpenConnect integration and related features
- Deleted the aetheris-openconnect crate and its dependencies from the project. - Updated contributing documentation to reflect the removal of OpenConnect integration. - Refactored aetheris-app to remove references to OpenConnect and adjusted related features and dependencies. - Updated LICENSE to reflect the current copyright holder. - Enhanced Kubernetes resource handling in aetheris-kube, including timeout handling for resource metrics. - Improved object detail display in aetheris-app to include container resource requests and limits. - Added tests for container resource extraction from Kubernetes objects.
1 parent a5b99f9 commit 4f476c6

25 files changed

Lines changed: 351 additions & 578 deletions

ARCHITECTURE.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ flowchart TD
1010
UI --> Relm[Relm4 App Component]
1111
Relm --> Commands[Async Commands and Streams]
1212
Commands --> KubeCrate[aetheris-kube]
13-
Commands -. optional VPN .-> OpenConnectCrate[aetheris-openconnect]
1413
KubeCrate --> Kubeconfig[Kubeconfig]
1514
KubeCrate --> Api[Kubernetes / OpenShift API]
1615
Relm --> Store[ProjectStore]
@@ -19,7 +18,7 @@ flowchart TD
1918
VTE --> Commands
2019
```
2120

22-
`aetheris-app` owns windows, widgets, user state, and persistence of Aetheris projects. `aetheris-kube` owns kubeconfig parsing, Kubernetes clients, discovery, list/watch, mutations, logs, exec, port-forwarding, metrics, and resource details. `aetheris-openconnect` is an optional native integration crate for libopenconnect; it isolates C FFI and exposes a Rust API for future VPN workflows.
21+
`aetheris-app` owns windows, widgets, user state, and persistence of Aetheris projects. `aetheris-kube` owns kubeconfig parsing, Kubernetes clients, discovery, list/watch, mutations, logs, exec, port-forwarding, metrics, and resource details.
2322

2423
## Crate Boundaries
2524

@@ -41,17 +40,10 @@ flowchart LR
4140
Ops[Logs exec port-forward mutations]
4241
end
4342
44-
subgraph OpenConnect["aetheris-openconnect"]
45-
SafeApi[Safe Rust API]
46-
Ffi[libopenconnect FFI]
47-
end
48-
4943
Widgets --> State
5044
State --> Commands
5145
State --> Streams
5246
Commands --> Manager
53-
Commands -. optional .-> SafeApi
54-
SafeApi --> Ffi
5547
Streams --> Manager
5648
Manager --> Session
5749
Session --> Resources
@@ -60,7 +52,7 @@ flowchart LR
6052
Projects --> State
6153
```
6254

63-
The backend crate must not import GTK, Adwaita, Relm4, VTE, or application widgets. Shared data crosses the boundary through DTOs exported from `aetheris-kube::types`. Native C integrations are kept out of both UI widgets and `aetheris-kube`; each integration gets a focused crate such as `aetheris-openconnect`, with `unsafe` declarations confined to its FFI module.
55+
The backend crate must not import GTK, Adwaita, Relm4, VTE, or application widgets. Shared data crosses the boundary through DTOs exported from `aetheris-kube::types`.
6456

6557
## Application Lifecycle
6658

CONTRIBUTING.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,6 @@ sudo dnf install -y \
1313
openssl-devel
1414
```
1515

16-
OpenConnect integration is optional while the VPN UI is under development. To
17-
build it locally, install the libopenconnect development files and enable the
18-
feature:
19-
20-
```sh
21-
sudo dnf install -y openconnect-devel
22-
cargo check -p aetheris-openconnect --features system-libopenconnect
23-
cargo check -p aetheris-app --features openconnect
24-
```
25-
2616
Run the app:
2717

2818
```sh
@@ -66,7 +56,6 @@ Aetheris has two Rust crates:
6656

6757
- `aetheris-kube` — pure Kubernetes backend. It must not depend on GTK, Relm4, Libadwaita, or VTE.
6858
- `aetheris-app` — Relm4/GTK4 application. It owns UI state, widgets, project persistence, and command wiring.
69-
- `aetheris-openconnect` — optional libopenconnect integration. It owns C FFI and exposes only safe Rust types to the app.
7059

7160
See [ARCHITECTURE.md](ARCHITECTURE.md) for diagrams and module responsibilities.
7261

Cargo.lock

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ resolver = "2"
33
members = [
44
"crates/aetheris-app",
55
"crates/aetheris-kube",
6-
"crates/aetheris-openconnect",
76
]
87

98
[workspace.package]

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [yyyy] [name of copyright owner]
189+
Copyright 2026 LuminusOS
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

crates/aetheris-app/Cargo.toml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,9 @@ resources = [
5555

5656
[features]
5757
default = []
58-
openconnect = [
59-
"dep:aetheris-openconnect",
60-
"aetheris-openconnect/system-libopenconnect",
61-
]
6258

6359
[dependencies]
6460
aetheris-kube = { path = "../aetheris-kube" }
65-
aetheris-openconnect = { path = "../aetheris-openconnect", optional = true }
6661
anyhow = "1"
6762
dirs = "6"
6863
futures = "0.3"

crates/aetheris-app/src/app.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ use std::{
55
};
66

77
use aetheris_kube::{
8-
AddClusterRequest, ClusterSummary, ContainerUsage, ContextInfo, KubeManager, ObjectCondition,
9-
ObjectDetail, ObjectEvent, ObjectSummary, ObjectWatchEvent, PodExecEvent, PodExecRequest,
10-
PodLogRequest, PodPortForwardEvent, PodPortForwardRequest, ResourceKind, ResourceUsage,
8+
AddClusterRequest, ClusterSummary, ContainerResources, ContainerUsage, ContextInfo,
9+
KubeManager, ObjectCondition, ObjectDetail, ObjectEvent, ObjectSummary, ObjectWatchEvent,
10+
PodExecEvent, PodExecRequest, PodLogRequest, PodPortForwardEvent, PodPortForwardRequest,
11+
ResourceKind, ResourceUsage,
1112
};
1213
use futures::FutureExt;
1314
use futures::future::{AbortHandle, Abortable};
@@ -178,6 +179,7 @@ pub struct App {
178179
object_columns: Vec<(ObjectTableColumn, gtk::ColumnViewColumn)>,
179180
object_list_stack: gtk::Stack,
180181
detail: DetailPane,
182+
object_load_token: u64,
181183
object_watch_token: u64,
182184
object_watch_abort_handle: Option<AbortHandle>,
183185
log_streaming: bool,
@@ -308,7 +310,7 @@ pub enum AppMsg {
308310
CaFileLoaded(Result<String, String>),
309311
ShowImportFile,
310312
Refresh,
311-
ObjectsLoaded(Result<Vec<ObjectSummary>, String>),
313+
ObjectsLoaded(u64, Result<Vec<ObjectSummary>, String>),
312314
AddCluster,
313315
ClusterAdded(Result<(String, String), String>),
314316
StateLoadedForCluster(String, Result<LoadedState, String>),

crates/aetheris-app/src/app/commands.rs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
use std::time::Duration;
2+
13
use super::utils::*;
24
use super::*;
35

6+
const CLUSTER_LOAD_TIMEOUT: Duration = Duration::from_secs(30);
7+
48
pub(super) async fn load_state() -> AppMsg {
59
let result = async {
610
// A missing kubeconfig is the normal first-run state — the user
@@ -34,29 +38,39 @@ pub(super) async fn load_state() -> AppMsg {
3438
}
3539

3640
pub(super) async fn load_cluster(context: String) -> AppMsg {
37-
let result = async {
38-
let manager = KubeManager::load()?;
39-
let session = manager.connect_context(&context).await?;
40-
let (namespaces, namespace_warning) = match session.list_namespaces().await {
41-
Ok(namespaces) => (namespaces, None),
42-
Err(error) => (
43-
manager.namespace_for_context(&context),
44-
Some(format_error(error)),
45-
),
46-
};
47-
let resources = session.discover_resources().await?;
48-
Ok::<_, anyhow::Error>(ClusterState {
49-
namespaces,
50-
resources,
51-
namespace_warning,
52-
})
53-
}
41+
let result = match tokio::time::timeout(CLUSTER_LOAD_TIMEOUT, async {
42+
load_cluster_state(context).await
43+
})
5444
.await
45+
{
46+
Ok(result) => result,
47+
Err(_) => Err(anyhow::anyhow!(
48+
"Timed out while discovering Kubernetes resources for this cluster. Check that the API server is reachable and try again."
49+
)),
50+
}
5551
.map_err(format_error);
5652

5753
AppMsg::ClusterLoaded(result)
5854
}
5955

56+
async fn load_cluster_state(context: String) -> anyhow::Result<ClusterState> {
57+
let manager = KubeManager::load()?;
58+
let session = manager.connect_context(&context).await?;
59+
let (namespaces, namespace_warning) = match session.list_namespaces().await {
60+
Ok(namespaces) => (namespaces, None),
61+
Err(error) => (
62+
manager.namespace_for_context(&context),
63+
Some(format_error(error)),
64+
),
65+
};
66+
let resources = session.discover_resources().await?;
67+
Ok(ClusterState {
68+
namespaces,
69+
resources,
70+
namespace_warning,
71+
})
72+
}
73+
6074
pub(super) async fn load_cluster_summary(context: String) -> AppMsg {
6175
let result = async {
6276
let manager = KubeManager::load()?;
@@ -70,13 +84,14 @@ pub(super) async fn load_cluster_summary(context: String) -> AppMsg {
7084
}
7185

7286
pub(super) async fn list_objects(
87+
token: u64,
7388
context: String,
7489
resource: ResourceKind,
7590
namespace: Option<String>,
7691
) -> AppMsg {
7792
let result = list_objects_snapshot(context, resource, namespace).await;
7893

79-
AppMsg::ObjectsLoaded(result)
94+
AppMsg::ObjectsLoaded(token, result)
8095
}
8196

8297
pub(super) async fn list_objects_snapshot(

crates/aetheris-app/src/app/component.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,7 @@ impl Component for App {
971971
node_unschedulable: None,
972972
request_token: 0,
973973
},
974+
object_load_token: 0,
974975
object_watch_token: 0,
975976
object_watch_abort_handle: None,
976977
log_streaming: false,

crates/aetheris-app/src/app/handler.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,7 +1127,10 @@ impl App {
11271127
self.refresh_objects(sender);
11281128
}
11291129
}
1130-
AppMsg::ObjectsLoaded(Ok(objects)) => {
1130+
AppMsg::ObjectsLoaded(token, Ok(objects)) => {
1131+
if token != self.object_load_token {
1132+
return;
1133+
}
11311134
self.loading = false;
11321135
let count = objects.len();
11331136
self.objects = objects;
@@ -1136,7 +1139,10 @@ impl App {
11361139
self.rebuild_object_list();
11371140
self.start_object_watch(sender);
11381141
}
1139-
AppMsg::ObjectsLoaded(Err(error)) => {
1142+
AppMsg::ObjectsLoaded(token, Err(error)) => {
1143+
if token != self.object_load_token {
1144+
return;
1145+
}
11401146
self.loading = false;
11411147
self.stop_object_watch();
11421148
self.objects.clear();

0 commit comments

Comments
 (0)