Skip to content

Commit

Permalink
add partial cluster-setup, only helm operator for now
Browse files Browse the repository at this point in the history
Signed-off-by: Robert Detjens <[email protected]>
  • Loading branch information
detjensrobert committed Jan 6, 2025
1 parent 640daf3 commit c4c1967
Show file tree
Hide file tree
Showing 11 changed files with 884 additions and 30 deletions.
319 changes: 294 additions & 25 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ futures-util = "0.3.30"
kube = { version = "0.91.0", features = ["runtime", "derive"] }
k8s-openapi = { version = "0.22.0", features = ["latest"] }
tokio = { version = "1.38.0", features = ["rt", "macros"] }
reqwest = { version = "0.12", default-features = false, features = [
"http2",
"rustls-tls",
] }
http = { version = "1.2", default-features = false }

# docker:
bollard = "0.16.1"
Expand Down
9 changes: 8 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub enum Commands {
/// Validate contents of rcds.yaml and any challenge.yaml files.
Validate, // no args

/// Checks access to various frontend/backend components.
/// Check access to various frontend/backend components.
CheckAccess {
/// Deployment profile to check
#[arg(short, long, value_name = "PROFILE", default_value = "all")]
Expand All @@ -72,4 +72,11 @@ pub enum Commands {
#[arg(short, long, help = "Check S3 asset bucket access and permissions")]
bucket: bool,
},

/// Set up required cluster resources (ingress, cert-manager, etc)
ClusterSetup {
/// Deployment profile to use
#[arg(short, long, value_name = "PROFILE")]
profile: String,
},
}
58 changes: 55 additions & 3 deletions src/clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

use anyhow::{anyhow, bail, Ok, Result};
use bollard;
use kube;
use futures_util::TryFutureExt;
use kube::{
self,
api::{DynamicObject, GroupVersionKind, TypeMeta},
core::ResourceExt,
discovery::{ApiCapabilities, ApiResource, Discovery, Scope},
};
use simplelog::*;

use crate::configparser::config;
Expand Down Expand Up @@ -67,8 +73,54 @@ pub async fn kube_client(profile: &config::ProfileConfig) -> Result<kube::Client
None => kube::Config::from_kubeconfig(&options).await?,
};

// client::try_from returns a Result, but the Error is not compatible
// with anyhow::Error, so assign this with ? and return Ok() separately
let client = kube::Client::try_from(client_config)?;

// check kube api readiness endpoint to make sure its reachable
let ready_req = http::Request::get("/readyz").body(vec![]).unwrap();
if client.request_text(ready_req).await.map_err(|e| {
// change 'Connection refused' error into something more helpful
// anyhow!("could not connect to Kubernetes (is KUBECONFIG or KUBECONTEXT correct?)")
e
})? != "ok"
{
bail!("kubernetes is not ready")
};

Ok(client)
}

/// Create a Kube API client for the passed object's resource type
pub async fn kube_api_for(
kube_object: &DynamicObject,
client: kube::Client,
) -> Result<kube::Api<DynamicObject>> {
let ns = kube_object.metadata.namespace.as_deref();

let gvk = if let Some(tm) = &kube_object.types {
GroupVersionKind::try_from(tm)?
} else {
bail!(
"cannot apply object without valid TypeMeta {:?}",
kube_object
);
};

let name = kube_object.name_any();
let (resource, caps) = kube::discovery::pinned_kind(&client, &gvk)
.await
// .with_context(|| {
// format!(
// "could not find resource type {:?} on cluster",
// kube_object.types.unwrap_or(TypeMeta::default())
// )
// })
?;

if caps.scope == kube::discovery::Scope::Cluster {
Ok(kube::Api::all_with(client, &resource))
} else if let Some(namespace) = ns {
Ok(kube::Api::namespaced_with(client, namespace, &resource))
} else {
Ok(kube::Api::default_namespaced_with(client, &resource))
}
}
Loading

0 comments on commit c4c1967

Please sign in to comment.