Skip to content

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

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

BigLullu
Copy link
Contributor

decoupled Client from kube.rs in CredentialsStore and Credentials and
added unit test leveraging on achieved decoupling

@Razz4780 Razz4780 requested a review from meowjesty June 25, 2025 12:41
@Razz4780
Copy link
Contributor

Skimmed through the PR:

  1. Need to make sure that unit tests use fresh tempdirs, not ~/.mirrord
  2. Need a test for scenario:
    • Folder empty, no credentials file
    • mirrord session - operator fingerprint F1, operator subscription id S1 (should request user cert)
    • mirrord session - operator fingerprint F1, operator subscription id S1 (should reuse user cert)
    • mirrord session - operator fingerprint F2, operator subscription id S1 (should request user cert, but reuse private key)
    • mirrord session - operator fingerprint F2, operator subscription id S1 (should reuse user cert)
  3. Need a test for scenario:
    • Folder empty, no credentials file
    • mirrord session - operator fingerprint F1, operator subscription id S1 (should request user cert)
    • mirrord session - operator fingerprint F1, operator subscription id S1 (should reuse user cert)
    • mirrord session - operator fingerprint F2, operator subscription id S1 (should request user cert, with new private key)
    • mirrord session - operator fingerprint F2, operator subscription id S1 (should reuse user cert)

Each simulated mirrord session should go through the whole flow, starting from loading the credentials file.

@meowjesty

Copy link
Member

@meowjesty meowjesty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few questions, have not looked into the tests yet.

@@ -27,3 +27,5 @@ pub mod credentials;
pub mod error;
/// Public/Private key abstraction for serialization and deserialization
pub mod key_pair;

pub use cluster_api::AuthClient;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: both cluster_api and AuthClient are already pub right? so why re-export?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd hide cluster_api here n reexport AuthClient since is a pub trait, do you agree ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, somehow missed this comment.

Sure.


//use kube::{api::PostParams, Api, Client, Resource};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed.

&self,
key_pair: &KeyPair,
common_name: &str,
) -> impl Future<Output = Result<Certificate, CredentialStoreError>> + Send;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have async fn in traits?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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).
I completely agree with the point about complexity. In this case, I'd say the complexity isn’t particularly high, but we don’t really have a way to measure it objectively, so… xD.
It does tend to hide complexity, though: one for all, the fact that two futures cannot share the same type to the compiler, can only belong to the same family(like closures).
Just sharing thoughts, of course :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's like that in the intproxy mostly due to it being a more unstable thing at the time, and we've been trying to avoid adding features so one day we can get back on stable rust (a bit of mirrord project background/backstory here).

About complexity, yeah it's not high, but the implementation we have wouldn't it look more like a normal function with async? Like the error handling could be done with just ? instead of match, and the async move part be dropped completely?

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?)

Copy link
Member

Choose a reason for hiding this comment

The 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 impl Future would be better, then maybe we can bring it up in the next sync and come to an agreement with the team?

Copy link
Contributor

Choose a reason for hiding this comment

The 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 Send, and clippy complains (because the trait is mostly unusable in async code).
While when you use the fn name() -> impl Future<...> + ... syntax, you can add trait bounds on the returned future.

Copy link
Member

Choose a reason for hiding this comment

The 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?

R: for<'de> Deserialize<'de> + Resource + Clone + Debug,
<R as Resource>::DynamicType: Default,
{
fn obtain_certificate(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think async would simplify this impl, or am I misunderstanding something here?


use crate::{certificate::Certificate, error::CredentialStoreError, key_pair::KeyPair};

pub trait AuthClient<R> {
Copy link
Member

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 the Client impl is part of the client feature, right? If I'm understanding this correctly, then I think AuthClient should be moved up (to some upper mod, which I guess it's lib.rs), and we could feature gate this whole mod with client?

Copy link
Member

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 ?

Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants