Skip to content
Closed
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
82 changes: 69 additions & 13 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,22 @@

//! Handle reading .kube/config files

use certs::{get_cert, get_cert_from_pem, get_key_from_str, get_private_key};
use chrono::{DateTime, Local, TimeZone};
use chrono::offset::Utc;
use duct::cmd;
use error::{KubeErrNo, KubeError};
use kube::{Kluster, KlusterAuth};
use serde_json::{self, Value};
use serde_yaml;

use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::From;
use std::env;
use std::error::Error;
use std::fs::File;
use std::io::{self, BufReader, Read};

use error::{KubeErrNo, KubeError};
use kube::{Kluster, KlusterAuth};
use certs::{get_cert, get_cert_from_pem, get_key_from_str, get_private_key};
use std::process::Command;

/// Kubernetes cluster config
#[derive(Debug, Deserialize)]
Expand Down Expand Up @@ -108,6 +107,56 @@ pub struct AuthProvider {
pub config: AuthProviderConfig,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Exec {
apiVersion: String,
pub args: Option<Vec<String>>,
pub command: Option<String>,
pub env: Option<Vec<Env>>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Env {
name: String,
value: String,
}

#[derive(Serialize, Deserialize)]
struct Spec {}

#[derive(Serialize, Deserialize)]
struct Status {
token: String,
}

#[derive(Serialize, Deserialize)]
struct AWSCredential {
kind: String,
apiVersion: String,
spec: Spec,
status: Status,
}

impl Exec {
pub fn generate_token(&self) -> String {
let mut filtered_env : HashMap<String, String> = HashMap::new();
for e in self.env.clone().unwrap(){
filtered_env.insert(e.name, e.value);
}

let output = Command::new(self.command.clone().unwrap())
.args(self.args.clone().unwrap())
.envs(filtered_env)
.output()
.expect("failed to execute process");

let out: String = String::from_utf8_lossy(&output.stdout).to_string();
let v: AWSCredential = serde_json::from_str(&out).unwrap();
let token = v.status.token;
return token;
}
}

impl AuthProvider {
// Copy the token and expiry out of the config into the refcells
fn copy_up(&self) {
Expand Down Expand Up @@ -254,6 +303,7 @@ pub struct IUserConf {

pub username: Option<String>,
pub password: Option<String>,
pub exec: Option<Exec>,

#[serde(rename = "auth-provider")] pub auth_provider: Option<AuthProvider>,
}
Expand All @@ -268,6 +318,7 @@ pub enum UserConf {
KeyCertPath(String, String),
KeyCertData(String, String),
UserPass(String, String),
Exec(Exec),
AuthProvider(AuthProvider),
Unsupported,
}
Expand All @@ -278,15 +329,17 @@ impl From<IUserConf> for UserConf {
UserConf::Token(token)
} else if let (Some(username), Some(password)) = (iconf.username, iconf.password) {
UserConf::UserPass(username, password)
} else if let Some(exec) = iconf.exec {
UserConf::Exec(exec)
} else if let (Some(client_cert_path), Some(key_path)) =
(iconf.client_cert, iconf.client_key)
{
UserConf::KeyCertPath(client_cert_path, key_path)
} else if let (Some(client_cert_data), Some(key_data)) =
(iconf.client_cert_data, iconf.client_key_data)
{
UserConf::KeyCertData(client_cert_data, key_data)
} else if let Some(auth_provider) = iconf.auth_provider {
(iconf.client_cert, iconf.client_key)
{
UserConf::KeyCertPath(client_cert_path, key_path)
} else if let (Some(client_cert_data), Some(key_data)) =
(iconf.client_cert_data, iconf.client_key_data)
{
UserConf::KeyCertData(client_cert_data, key_data)
} else if let Some(auth_provider) = iconf.auth_provider {
UserConf::AuthProvider(auth_provider)
} else {
UserConf::Unsupported
Expand Down Expand Up @@ -523,6 +576,9 @@ impl Config {
&UserConf::UserPass(ref username, ref password) => {
Ok(KlusterAuth::with_userpass(username, password))
}
&UserConf::Exec(ref exec) => {
Ok(KlusterAuth::with_exec(exec.clone()))
}
&UserConf::KeyCertPath(ref cert_path, ref key_path) => {
auth_from_paths(
cert_path.clone(),
Expand Down
33 changes: 24 additions & 9 deletions src/kube.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
use ansi_term::Colour::{Green, Red, Yellow};
use chrono::DateTime;
use chrono::offset::Utc;
use config::AuthProvider;
use config::Exec;
use connector::ClickSslConnector;
use error::{KubeErrNo, KubeError};
use hyper::{Client, Url};
use hyper::client::{Body, RequestBuilder};
use hyper::client::request::Request;
Expand All @@ -25,22 +29,17 @@ use hyper::header::{Authorization, Basic, Bearer};
use hyper::method::Method;
use hyper::status::StatusCode;
use hyper_rustls::TlsClient;
use rustls::{self, Certificate, PrivateKey};
use serde::Deserialize;
use serde_json;
use serde_json::{Map, Value};
use rustls::{self, Certificate, PrivateKey};

use std::fmt;
use std::io::BufReader;
use std::net::IpAddr;
use std::str::FromStr;
use std::sync::Arc;
use std::time::Duration;

use config::AuthProvider;
use connector::ClickSslConnector;
use error::{KubeErrNo, KubeError};

// Various things we can return from the kubernetes api

// objects
Expand Down Expand Up @@ -339,6 +338,7 @@ pub struct JobList {
pub enum KlusterAuth {
Token(String),
UserPass(String, String),
Exec(Exec),
CertKey(Vec<Certificate>, PrivateKey),
AuthProvider(AuthProvider),
}
Expand All @@ -352,6 +352,10 @@ impl KlusterAuth {
KlusterAuth::UserPass(user.to_owned(), pass.to_owned())
}

pub fn with_exec(exec: Exec) -> KlusterAuth {
KlusterAuth::Exec(exec.to_owned())
}

pub fn with_cert_and_key(cert: Certificate, private_key: PrivateKey) -> KlusterAuth {
KlusterAuth::CertKey(vec![cert], private_key)
}
Expand All @@ -371,6 +375,7 @@ pub struct Kluster {

// NoCertificateVerification struct/impl taken from the rustls example code
struct NoCertificateVerification {}

impl rustls::ServerCertVerifier for NoCertificateVerification {
fn verify_server_cert(
&self,
Expand Down Expand Up @@ -466,6 +471,10 @@ impl Kluster {
username: user.clone(),
password: Some(pass.clone()),
})),
KlusterAuth::Exec(ref exec) => req.header(Authorization(Bearer {
//TODO
token: exec.generate_token(),
})),
KlusterAuth::CertKey(..) => req,
}
}
Expand Down Expand Up @@ -521,8 +530,8 @@ impl Kluster {

/// Get a resource and deserialize it as a T
pub fn get<T>(&self, path: &str) -> Result<T, KubeError>
where
for<'de> T: Deserialize<'de>,
where
for<'de> T: Deserialize<'de>,
{
let resp = try!(self.send_req(path));
let resp = try!(self.check_resp(resp));
Expand All @@ -534,7 +543,7 @@ impl Kluster {
pub fn get_read(&self, path: &str, timeout: Option<Duration>) -> Result<Response, KubeError> {
if timeout.is_some() {
let url = try!(self.endpoint.join(path));
let mut req = try!(Request::with_connector(Method::Get, url, &self.connector,));
let mut req = try!(Request::with_connector(Method::Get, url, &self.connector));
{
// scope for mutable borrow of req
let headers = req.headers_mut();
Expand All @@ -557,6 +566,12 @@ impl Kluster {
password: Some(pass.clone()),
}));
}
KlusterAuth::Exec(ref exec) => {
headers.set(Authorization(Bearer {
//TODO
token: exec.generate_token(),
}));
}
KlusterAuth::CertKey(..) => {}
}
}
Expand Down