Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 17 additions & 7 deletions crates/openshell-cli/tests/ensure_providers_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ use openshell_core::proto::open_shell_server::{OpenShell, OpenShellServer};
use openshell_core::proto::{
CreateProviderRequest, CreateSandboxRequest, CreateSshSessionRequest, CreateSshSessionResponse,
DeleteProviderRequest, DeleteProviderResponse, DeleteSandboxRequest, DeleteSandboxResponse,
ExecSandboxEvent, ExecSandboxRequest, GetGatewayConfigRequest, GetGatewayConfigResponse,
GetProviderRequest, GetSandboxConfigRequest, GetSandboxConfigResponse,
GetSandboxProviderEnvironmentRequest, GetSandboxProviderEnvironmentResponse, GetSandboxRequest,
HealthRequest, HealthResponse, ListProvidersRequest, ListProvidersResponse,
ListSandboxesRequest, ListSandboxesResponse, Provider, ProviderResponse,
RevokeSshSessionRequest, RevokeSshSessionResponse, SandboxResponse, SandboxStreamEvent,
ServiceStatus, UpdateProviderRequest, WatchSandboxRequest,
ExecSandboxEvent, ExecSandboxRequest, GatewayMessage, GetGatewayConfigRequest,
GetGatewayConfigResponse, GetProviderRequest, GetSandboxConfigRequest,
GetSandboxConfigResponse, GetSandboxProviderEnvironmentRequest,
GetSandboxProviderEnvironmentResponse, GetSandboxRequest, HealthRequest, HealthResponse,
ListProvidersRequest, ListProvidersResponse, ListSandboxesRequest, ListSandboxesResponse,
Provider, ProviderResponse, RevokeSshSessionRequest, RevokeSshSessionResponse, SandboxResponse,
SandboxStreamEvent, ServiceStatus, SupervisorMessage, UpdateProviderRequest,
WatchSandboxRequest,
};
use rcgen::{
BasicConstraints, Certificate, CertificateParams, ExtendedKeyUsagePurpose, IsCa, KeyPair,
Expand Down Expand Up @@ -298,6 +299,8 @@ impl OpenShell for TestOpenShell {
tokio_stream::wrappers::ReceiverStream<Result<SandboxStreamEvent, Status>>;
type ExecSandboxStream =
tokio_stream::wrappers::ReceiverStream<Result<ExecSandboxEvent, Status>>;
type ConnectSupervisorStream =
tokio_stream::wrappers::ReceiverStream<Result<GatewayMessage, Status>>;

async fn watch_sandbox(
&self,
Expand Down Expand Up @@ -423,6 +426,13 @@ impl OpenShell for TestOpenShell {
) -> Result<Response<openshell_core::proto::GetDraftHistoryResponse>, Status> {
Err(Status::unimplemented("not implemented in test"))
}

async fn connect_supervisor(
&self,
_request: tonic::Request<tonic::Streaming<SupervisorMessage>>,
) -> Result<Response<Self::ConnectSupervisorStream>, Status> {
Err(Status::unimplemented("not implemented in test"))
}
}

// ── TLS helpers ──────────────────────────────────────────────────────
Expand Down
10 changes: 10 additions & 0 deletions crates/openshell-cli/tests/mtls_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ impl OpenShell for TestOpenShell {
>;
type ExecSandboxStream =
tokio_stream::wrappers::ReceiverStream<Result<ExecSandboxEvent, Status>>;
type ConnectSupervisorStream = tokio_stream::wrappers::ReceiverStream<
Result<openshell_core::proto::GatewayMessage, Status>,
>;

async fn watch_sandbox(
&self,
Expand Down Expand Up @@ -325,6 +328,13 @@ impl OpenShell for TestOpenShell {
) -> Result<Response<openshell_core::proto::GetDraftHistoryResponse>, Status> {
Err(Status::unimplemented("not implemented in test"))
}

async fn connect_supervisor(
&self,
_request: tonic::Request<tonic::Streaming<openshell_core::proto::SupervisorMessage>>,
) -> Result<Response<Self::ConnectSupervisorStream>, Status> {
Err(Status::unimplemented("not implemented in test"))
}
}

fn build_ca() -> (Certificate, KeyPair) {
Expand Down
24 changes: 17 additions & 7 deletions crates/openshell-cli/tests/provider_commands_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ use openshell_core::proto::open_shell_server::{OpenShell, OpenShellServer};
use openshell_core::proto::{
CreateProviderRequest, CreateSandboxRequest, CreateSshSessionRequest, CreateSshSessionResponse,
DeleteProviderRequest, DeleteProviderResponse, DeleteSandboxRequest, DeleteSandboxResponse,
ExecSandboxEvent, ExecSandboxRequest, GetGatewayConfigRequest, GetGatewayConfigResponse,
GetProviderRequest, GetSandboxConfigRequest, GetSandboxConfigResponse,
GetSandboxProviderEnvironmentRequest, GetSandboxProviderEnvironmentResponse, GetSandboxRequest,
HealthRequest, HealthResponse, ListProvidersRequest, ListProvidersResponse,
ListSandboxesRequest, ListSandboxesResponse, Provider, ProviderResponse,
RevokeSshSessionRequest, RevokeSshSessionResponse, SandboxResponse, SandboxStreamEvent,
ServiceStatus, UpdateProviderRequest, WatchSandboxRequest,
ExecSandboxEvent, ExecSandboxRequest, GatewayMessage, GetGatewayConfigRequest,
GetGatewayConfigResponse, GetProviderRequest, GetSandboxConfigRequest,
GetSandboxConfigResponse, GetSandboxProviderEnvironmentRequest,
GetSandboxProviderEnvironmentResponse, GetSandboxRequest, HealthRequest, HealthResponse,
ListProvidersRequest, ListProvidersResponse, ListSandboxesRequest, ListSandboxesResponse,
Provider, ProviderResponse, RevokeSshSessionRequest, RevokeSshSessionResponse, SandboxResponse,
SandboxStreamEvent, ServiceStatus, SupervisorMessage, UpdateProviderRequest,
WatchSandboxRequest,
};
use rcgen::{
BasicConstraints, Certificate, CertificateParams, ExtendedKeyUsagePurpose, IsCa, KeyPair,
Expand Down Expand Up @@ -252,6 +253,8 @@ impl OpenShell for TestOpenShell {
tokio_stream::wrappers::ReceiverStream<Result<SandboxStreamEvent, Status>>;
type ExecSandboxStream =
tokio_stream::wrappers::ReceiverStream<Result<ExecSandboxEvent, Status>>;
type ConnectSupervisorStream =
tokio_stream::wrappers::ReceiverStream<Result<GatewayMessage, Status>>;

async fn watch_sandbox(
&self,
Expand Down Expand Up @@ -377,6 +380,13 @@ impl OpenShell for TestOpenShell {
) -> Result<Response<openshell_core::proto::GetDraftHistoryResponse>, Status> {
Err(Status::unimplemented("not implemented in test"))
}

async fn connect_supervisor(
&self,
_request: tonic::Request<tonic::Streaming<SupervisorMessage>>,
) -> Result<Response<Self::ConnectSupervisorStream>, Status> {
Err(Status::unimplemented("not implemented in test"))
}
}

fn install_rustls_provider() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use openshell_core::proto::open_shell_server::{OpenShell, OpenShellServer};
use openshell_core::proto::{
CreateProviderRequest, CreateSandboxRequest, CreateSshSessionRequest, CreateSshSessionResponse,
DeleteProviderRequest, DeleteProviderResponse, DeleteSandboxRequest, DeleteSandboxResponse,
ExecSandboxEvent, ExecSandboxRequest, GetGatewayConfigRequest, GetGatewayConfigResponse,
GetProviderRequest, GetSandboxConfigRequest, GetSandboxConfigResponse,
GetSandboxProviderEnvironmentRequest, GetSandboxProviderEnvironmentResponse, GetSandboxRequest,
HealthRequest, HealthResponse, ListProvidersRequest, ListProvidersResponse,
ListSandboxesRequest, ListSandboxesResponse, PlatformEvent, ProviderResponse,
RevokeSshSessionRequest, RevokeSshSessionResponse, Sandbox, SandboxPhase, SandboxResponse,
SandboxStreamEvent, ServiceStatus, UpdateProviderRequest, WatchSandboxRequest,
sandbox_stream_event,
ExecSandboxEvent, ExecSandboxRequest, GatewayMessage, GetGatewayConfigRequest,
GetGatewayConfigResponse, GetProviderRequest, GetSandboxConfigRequest,
GetSandboxConfigResponse, GetSandboxProviderEnvironmentRequest,
GetSandboxProviderEnvironmentResponse, GetSandboxRequest, HealthRequest, HealthResponse,
ListProvidersRequest, ListProvidersResponse, ListSandboxesRequest, ListSandboxesResponse,
PlatformEvent, ProviderResponse, RevokeSshSessionRequest, RevokeSshSessionResponse, Sandbox,
SandboxPhase, SandboxResponse, SandboxStreamEvent, ServiceStatus, SupervisorMessage,
UpdateProviderRequest, WatchSandboxRequest, sandbox_stream_event,
};
use rcgen::{
BasicConstraints, Certificate, CertificateParams, ExtendedKeyUsagePurpose, IsCa, KeyPair,
Expand Down Expand Up @@ -242,6 +242,8 @@ impl OpenShell for TestOpenShell {
tokio_stream::wrappers::ReceiverStream<Result<SandboxStreamEvent, Status>>;
type ExecSandboxStream =
tokio_stream::wrappers::ReceiverStream<Result<ExecSandboxEvent, Status>>;
type ConnectSupervisorStream =
tokio_stream::wrappers::ReceiverStream<Result<GatewayMessage, Status>>;

async fn watch_sandbox(
&self,
Expand Down Expand Up @@ -403,6 +405,13 @@ impl OpenShell for TestOpenShell {
) -> Result<Response<openshell_core::proto::GetDraftHistoryResponse>, Status> {
Err(Status::unimplemented("not implemented in test"))
}

async fn connect_supervisor(
&self,
_request: tonic::Request<tonic::Streaming<SupervisorMessage>>,
) -> Result<Response<Self::ConnectSupervisorStream>, Status> {
Err(Status::unimplemented("not implemented in test"))
}
}

fn install_rustls_provider() {
Expand Down
22 changes: 16 additions & 6 deletions crates/openshell-cli/tests/sandbox_name_fallback_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ use openshell_core::proto::open_shell_server::{OpenShell, OpenShellServer};
use openshell_core::proto::{
CreateProviderRequest, CreateSandboxRequest, CreateSshSessionRequest, CreateSshSessionResponse,
DeleteProviderRequest, DeleteProviderResponse, DeleteSandboxRequest, DeleteSandboxResponse,
ExecSandboxEvent, ExecSandboxRequest, GetGatewayConfigRequest, GetGatewayConfigResponse,
GetProviderRequest, GetSandboxConfigRequest, GetSandboxConfigResponse,
GetSandboxProviderEnvironmentRequest, GetSandboxProviderEnvironmentResponse, GetSandboxRequest,
HealthRequest, HealthResponse, ListProvidersRequest, ListProvidersResponse,
ListSandboxesRequest, ListSandboxesResponse, ProviderResponse, Sandbox, SandboxResponse,
SandboxStreamEvent, ServiceStatus, UpdateProviderRequest, WatchSandboxRequest,
ExecSandboxEvent, ExecSandboxRequest, GatewayMessage, GetGatewayConfigRequest,
GetGatewayConfigResponse, GetProviderRequest, GetSandboxConfigRequest,
GetSandboxConfigResponse, GetSandboxProviderEnvironmentRequest,
GetSandboxProviderEnvironmentResponse, GetSandboxRequest, HealthRequest, HealthResponse,
ListProvidersRequest, ListProvidersResponse, ListSandboxesRequest, ListSandboxesResponse,
ProviderResponse, Sandbox, SandboxResponse, SandboxStreamEvent, ServiceStatus,
SupervisorMessage, UpdateProviderRequest, WatchSandboxRequest,
};
use rcgen::{
BasicConstraints, Certificate, CertificateParams, ExtendedKeyUsagePurpose, IsCa, KeyPair,
Expand Down Expand Up @@ -210,6 +211,8 @@ impl OpenShell for TestOpenShell {
tokio_stream::wrappers::ReceiverStream<Result<SandboxStreamEvent, Status>>;
type ExecSandboxStream =
tokio_stream::wrappers::ReceiverStream<Result<ExecSandboxEvent, Status>>;
type ConnectSupervisorStream =
tokio_stream::wrappers::ReceiverStream<Result<GatewayMessage, Status>>;

async fn watch_sandbox(
&self,
Expand Down Expand Up @@ -335,6 +338,13 @@ impl OpenShell for TestOpenShell {
) -> Result<Response<openshell_core::proto::GetDraftHistoryResponse>, Status> {
Err(Status::unimplemented("not implemented in test"))
}

async fn connect_supervisor(
&self,
_request: tonic::Request<tonic::Streaming<SupervisorMessage>>,
) -> Result<Response<Self::ConnectSupervisorStream>, Status> {
Err(Status::unimplemented("not implemented in test"))
}
}

// ── helpers ───────────────────────────────────────────────────────────
Expand Down
69 changes: 3 additions & 66 deletions crates/openshell-driver-kubernetes/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use crate::config::KubernetesComputeConfig;
use futures::{Stream, StreamExt, TryStreamExt};
use k8s_openapi::api::core::v1::{Event as KubeEventObj, Node, Pod};
use k8s_openapi::api::core::v1::{Event as KubeEventObj, Node};
use kube::api::{Api, ApiResource, DeleteParams, ListParams, PostParams};
use kube::core::gvk::GroupVersionKind;
use kube::core::{DynamicObject, ObjectMeta};
Expand All @@ -15,12 +15,10 @@ use openshell_core::proto::compute::v1::{
DriverCondition as SandboxCondition, DriverPlatformEvent as PlatformEvent,
DriverSandbox as Sandbox, DriverSandboxSpec as SandboxSpec,
DriverSandboxStatus as SandboxStatus, DriverSandboxTemplate as SandboxTemplate,
GetCapabilitiesResponse, ResolveSandboxEndpointResponse, SandboxEndpoint,
WatchSandboxesDeletedEvent, WatchSandboxesEvent, WatchSandboxesPlatformEvent,
WatchSandboxesSandboxEvent, sandbox_endpoint, watch_sandboxes_event,
GetCapabilitiesResponse, WatchSandboxesDeletedEvent, WatchSandboxesEvent,
WatchSandboxesPlatformEvent, WatchSandboxesSandboxEvent, watch_sandboxes_event,
};
use std::collections::BTreeMap;
use std::net::IpAddr;
use std::pin::Pin;
use std::time::Duration;
use tokio::sync::mpsc;
Expand Down Expand Up @@ -271,21 +269,6 @@ impl KubernetesComputeDriver {
&self.config.ssh_handshake_secret
}

async fn agent_pod_ip(&self, pod_name: &str) -> Result<Option<IpAddr>, KubeError> {
let api: Api<Pod> = Api::namespaced(self.client.clone(), &self.config.namespace);
match api.get(pod_name).await {
Ok(pod) => {
let ip = pod
.status
.and_then(|status| status.pod_ip)
.and_then(|ip| ip.parse().ok());
Ok(ip)
}
Err(KubeError::Api(err)) if err.code == 404 => Ok(None),
Err(err) => Err(err),
}
}

pub async fn create_sandbox(&self, sandbox: &Sandbox) -> Result<(), KubernetesDriverError> {
let name = sandbox.name.as_str();
info!(
Expand Down Expand Up @@ -407,52 +390,6 @@ impl KubernetesComputeDriver {
}
}

pub async fn resolve_sandbox_endpoint(
&self,
sandbox: &Sandbox,
) -> Result<ResolveSandboxEndpointResponse, KubernetesDriverError> {
if let Some(status) = sandbox.status.as_ref()
&& !status.instance_id.is_empty()
{
match self.agent_pod_ip(&status.instance_id).await {
Ok(Some(ip)) => {
return Ok(ResolveSandboxEndpointResponse {
endpoint: Some(SandboxEndpoint {
target: Some(sandbox_endpoint::Target::Ip(ip.to_string())),
port: u32::from(self.config.ssh_port),
}),
});
}
Ok(None) => {
return Err(KubernetesDriverError::Precondition(
"sandbox agent pod IP is not available".to_string(),
));
}
Err(err) => {
return Err(KubernetesDriverError::Message(format!(
"failed to resolve agent pod IP: {err}"
)));
}
}
}

if sandbox.name.is_empty() {
return Err(KubernetesDriverError::Precondition(
"sandbox has no name".to_string(),
));
}

Ok(ResolveSandboxEndpointResponse {
endpoint: Some(SandboxEndpoint {
target: Some(sandbox_endpoint::Target::Host(format!(
"{}.{}.svc.cluster.local",
sandbox.name, self.config.namespace
))),
port: u32::from(self.config.ssh_port),
}),
})
}

pub async fn watch_sandboxes(&self) -> Result<WatchStream, String> {
let namespace = self.config.namespace.clone();
let sandbox_api = self.api();
Expand Down
18 changes: 1 addition & 17 deletions crates/openshell-driver-kubernetes/src/grpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ use futures::{Stream, StreamExt};
use openshell_core::proto::compute::v1::{
CreateSandboxRequest, CreateSandboxResponse, DeleteSandboxRequest, DeleteSandboxResponse,
GetCapabilitiesRequest, GetCapabilitiesResponse, GetSandboxRequest, GetSandboxResponse,
ListSandboxesRequest, ListSandboxesResponse, ResolveSandboxEndpointRequest,
ResolveSandboxEndpointResponse, StopSandboxRequest, StopSandboxResponse,
ListSandboxesRequest, ListSandboxesResponse, StopSandboxRequest, StopSandboxResponse,
ValidateSandboxCreateRequest, ValidateSandboxCreateResponse, WatchSandboxesEvent,
WatchSandboxesRequest, compute_driver_server::ComputeDriver,
};
Expand Down Expand Up @@ -128,21 +127,6 @@ impl ComputeDriver for ComputeDriverService {
Ok(Response::new(DeleteSandboxResponse { deleted }))
}

async fn resolve_sandbox_endpoint(
&self,
request: Request<ResolveSandboxEndpointRequest>,
) -> Result<Response<ResolveSandboxEndpointResponse>, Status> {
let sandbox = request
.into_inner()
.sandbox
.ok_or_else(|| Status::invalid_argument("sandbox is required"))?;
self.driver
.resolve_sandbox_endpoint(&sandbox)
.await
.map(Response::new)
.map_err(status_from_driver_error)
}

type WatchSandboxesStream =
Pin<Box<dyn Stream<Item = Result<WatchSandboxesEvent, Status>> + Send + 'static>>;

Expand Down
7 changes: 7 additions & 0 deletions crates/openshell-sandbox/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,15 @@ rcgen = { workspace = true }
webpki-roots = { workspace = true }

# HTTP
hyper = { workspace = true }
hyper-util = { workspace = true }
http = "1"
http-body-util = "0.1"
bytes = { workspace = true }

# UUID
uuid = { workspace = true }

# Encoding
base64 = { workspace = true }

Expand Down
5 changes: 5 additions & 0 deletions crates/openshell-sandbox/src/grpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ async fn connect_channel(endpoint: &str) -> Result<Channel> {
.wrap_err("failed to connect to OpenShell server")
}

/// Create a channel to the OpenShell server (public for use by supervisor_session).
pub async fn connect_channel_pub(endpoint: &str) -> Result<Channel> {
connect_channel(endpoint).await
}

/// Connect to the OpenShell server (mTLS or plaintext based on endpoint scheme).
async fn connect(endpoint: &str) -> Result<OpenShellClient<Channel>> {
let channel = connect_channel(endpoint).await?;
Expand Down
Loading
Loading