-
Notifications
You must be signed in to change notification settings - Fork 132
Mbe 776 decouple credentialstore from kubers and add more complex #3388
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
63610f5
e560490
d8ddcee
f1ebc84
76c1e3f
cb5b977
b143e2b
25a22f7
1c0d407
c1b4f0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
decoupled Client from kube.rs in CredentialsStore and Credentials and | ||
added unit test leveraging on achieved decoupling |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
use std::{fmt::Debug, future::Future}; | ||
|
||
use futures::{future, FutureExt}; | ||
use kube::{api::PostParams, Api, Client, Resource}; | ||
use serde::Deserialize; | ||
#[cfg(feature = "client")] | ||
use x509_certificate::{ | ||
rfc2986, InMemorySigningKeyPair, X509CertificateBuilder, X509CertificateError, | ||
}; | ||
|
||
use crate::{certificate::Certificate, error::CredentialStoreError, key_pair::KeyPair}; | ||
|
||
pub trait AuthClient<R> { | ||
fn obtain_certificate( | ||
&self, | ||
key_pair: &KeyPair, | ||
common_name: &str, | ||
) -> impl Future<Output = Result<Certificate, CredentialStoreError>> + Send; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't we have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here based on what I've seen in intproxy the code seems to be aligned with the project, that part at least (though I personally have some reservations about async in traits). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's like that in the About complexity, yeah it's not high, but the implementation we have wouldn't it look more like a normal function with let request = certificate_request(common_name, key_pair)?;
let certificate = request.encode_pem()?;
let api: Api<R> = Api::all(self.clone());
Ok(api.create_subresource("certificate", "operator", &PostParams::default(), certificate_request.into()).await?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't say this is a true blocker, we have not talked about it yet, so if you think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the correct syntax. You could write trait Whatever {
async fn something();
} But then you can implement this trait it in a way that makes the future not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can't we use https://crates.io/crates/async-trait for this then? |
||
} | ||
|
||
impl<R> AuthClient<R> for Client | ||
where | ||
R: for<'de> Deserialize<'de> + Resource + Clone + Debug, | ||
<R as Resource>::DynamicType: Default, | ||
{ | ||
fn obtain_certificate( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
&self, | ||
key_pair: &KeyPair, | ||
common_name: &str, | ||
) -> impl Future<Output = Result<Certificate, CredentialStoreError>> + Send { | ||
let certificate_request = match certificate_request(common_name, key_pair) | ||
.and_then(|req| req.encode_pem().map_err(X509CertificateError::from)) | ||
{ | ||
Ok(req) => req, | ||
Err(e) => return future::err(e.into()).boxed(), | ||
}; | ||
|
||
async move { | ||
let api: Api<R> = Api::all(self.clone()); | ||
|
||
api.create_subresource( | ||
"certificate", | ||
"operator", | ||
&PostParams::default(), | ||
certificate_request.into(), | ||
) | ||
.await | ||
.map_err(CredentialStoreError::from) | ||
} | ||
.boxed() | ||
} | ||
} | ||
|
||
fn certificate_request( | ||
common_name: &str, | ||
key_pair: &InMemorySigningKeyPair, | ||
) -> Result<rfc2986::CertificationRequest, X509CertificateError> { | ||
let mut builder = X509CertificateBuilder::default(); | ||
|
||
let _ = builder | ||
.subject() | ||
.append_common_name_utf8_string(common_name); | ||
|
||
builder.create_certificate_signing_request(key_pair) | ||
} | ||
|
||
#[cfg(test)] | ||
pub mod client_mock { | ||
use std::fmt::Debug; | ||
|
||
use kube::Resource; | ||
use serde::Deserialize; | ||
|
||
use crate::{ | ||
certificate::Certificate, error::CredentialStoreError, key_pair::KeyPair, AuthClient, | ||
}; | ||
|
||
#[derive(Clone)] | ||
pub struct ClientMock { | ||
pub return_error: bool, | ||
} | ||
|
||
impl<R> AuthClient<R> for ClientMock | ||
where | ||
R: for<'de> Deserialize<'de> + Resource + Clone + Debug, | ||
<R as Resource>::DynamicType: Default, | ||
{ | ||
async fn obtain_certificate( | ||
&self, | ||
_key_pair: &KeyPair, | ||
_common_name: &str, | ||
) -> Result<Certificate, CredentialStoreError> { | ||
if self.return_error { | ||
Err(CredentialStoreError::FileAccess(std::io::Error::new( | ||
std::io::ErrorKind::Other, | ||
"Mock Error", | ||
))) | ||
} else { | ||
Ok(certificate_mock()) | ||
} | ||
} | ||
} | ||
|
||
pub fn certificate_mock() -> Certificate { | ||
const SERIALIZED: &str = r#""-----BEGIN CERTIFICATE-----\r\nMIICGTCCAcmgAwIBAgIBATAHBgMrZXAFADBwMUIwQAYDVQQDDDlUaGUgTWljaGHF\r\ngiBTbW9sYXJlayBPcmdhbml6YXRpb25gcyBUZWFtcyBMaWNlbnNlIChUcmlhbCkx\r\nKjAoBgNVBAoMIVRoZSBNaWNoYcWCIFNtb2xhcmVrIE9yZ2FuaXphdGlvbjAeFw0y\r\nNDAyMDgxNTUwNDFaFw0yNDEyMjQwMDAwMDBaMBsxGTAXBgNVBAMMEHJheno0Nzgw\r\nLW1hY2hpbmUwLDAHBgMrZW4FAAMhAAfxTouyk5L5lB3eFwC5Rg9iI4KmQaFpnGVM\r\n2sYpv9HOo4HYMIHVMIHSBhcvbWV0YWxiZWFyL2xpY2Vuc2UvaW5mbwEB/wSBs3si\r\ndHlwZSI6InRlYW1zIiwibWF4X3NlYXRzIjpudWxsLCJzdWJzY3JpcHRpb25faWQi\r\nOiJmMWIxZDI2ZS02NGQzLTQ4YjYtYjVkMi05MzAxMzAwNWE3MmUiLCJvcmdhbml6\r\nYXRpb25faWQiOiIzNTdhZmE4MS0yN2QxLTQ3YjEtYTFiYS1hYzM1ZjlhM2MyNjMi\r\nLCJ0cmlhbCI6dHJ1ZSwidmVyc2lvbiI6IjMuNzMuMCJ9MAcGAytlcAUAA0EAJbbo\r\nu42KnHJBbPMYspMdv9ZdTQMixJgQUheNEs/o4+XfwgYOaRjCVQTzYs1m9f720WQ9\r\n4J04GdQvcu7B/oTgDQ==\r\n-----END CERTIFICATE-----\r\n""#; | ||
serde_yaml::from_str(SERIALIZED).unwrap() | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This trait is part of our
default-features
, while theClient
impl is part of theclient
feature, right? If I'm understanding this correctly, then I thinkAuthClient
should be moved up (to some upper mod, which I guess it'slib.rs
), and we could feature gate this wholemod
withclient
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to complicate things though (not a big fan of having
features
like this), so do we care @Razz4780 ?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's used only by code hidden behind the
client
feature, it should also be behind this feature