Skip to content
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

builder origin rbac subcommand #7841

Merged
merged 21 commits into from
Aug 12, 2020
Merged

builder origin rbac subcommand #7841

merged 21 commits into from
Aug 12, 2020

Conversation

jeremymv2
Copy link
Contributor

@jeremymv2 jeremymv2 commented Jul 28, 2020

Closes #7599
Companion to habitat-sh/builder#1431

Although there was a lot more potential structopt work to do, I had to stop myself and stash that effort as the blast radius became very broad (ie. AuthToken, Origin and BldrURL touch 90% of CLI commands).
To handle the remaining structopt work that will allow us to be more streamlined, I created #7866

Signed-off-by: Jeremy J. Miller [email protected]

@eeyun
Copy link
Contributor

eeyun commented Jul 29, 2020

Code looks good, but it does appear to have broken some unit tests. Otherwise its 👍 from me.

@jeremymv2 jeremymv2 added the Type:Feature PRs that add a new feature label Jul 29, 2020
@jeremymv2
Copy link
Contributor Author

@eeyun the unit tests are fixed up now.

Copy link
Contributor

@davidMcneil davidMcneil left a comment

Choose a reason for hiding this comment

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

Very nice; a great addition!

components/builder-api-client/src/lib.rs Show resolved Hide resolved
components/hab/src/cli/hab/origin.rs Outdated Show resolved Hide resolved
components/hab/src/cli/hab/origin.rs Outdated Show resolved Hide resolved
components/hab/src/cli/hab/origin.rs Outdated Show resolved Hide resolved
components/hab/src/cli/hab/origin.rs Outdated Show resolved Hide resolved
components/hab/src/cli/hab/origin.rs Outdated Show resolved Hide resolved
components/hab/src/cli.rs Outdated Show resolved Hide resolved
components/hab/src/cli/hab/origin.rs Outdated Show resolved Hide resolved
components/hab/src/main.rs Outdated Show resolved Hide resolved
@davidMcneil

This comment has been minimized.

@jeremymv2 jeremymv2 force-pushed the jeremymv2/rbac_subcommand branch from 9472ea6 to 4c94bd8 Compare August 11, 2020 13:37
components/core/src/util/text_render.rs Show resolved Hide resolved
fn tabify(mut tw: TabWriter<Vec<u8>>, s: &str) -> Result<String> {
write!(&mut tw, "{}", s)?;
tw.flush()?;
String::from_utf8(tw.into_inner().expect("TABWRITER into_inner")).map_err(|e| {
Copy link
Contributor

Choose a reason for hiding this comment

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

Because this function already returns a Result, could we remove this expect in favor of propagating the Err?

Copy link
Contributor Author

@jeremymv2 jeremymv2 Aug 12, 2020

Choose a reason for hiding this comment

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

Handled in 78f9d5e

components/core/src/origin.rs Outdated Show resolved Hide resolved
components/core/src/origin.rs Outdated Show resolved Hide resolved
components/core/Cargo.toml Outdated Show resolved Hide resolved
components/hab/src/cli/hab/util.rs Outdated Show resolved Hide resolved
components/hab/src/cli/hab/util.rs Outdated Show resolved Hide resolved
components/hab/src/cli/hab/util.rs Outdated Show resolved Hide resolved
})
}

pub fn bldr_url_from_args_env_load_or_default(opt: Option<Url>) -> String {
Copy link
Contributor

Choose a reason for hiding this comment

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

It is a bummer we lose type information here (ie Url to String). Could we make this return a Url?

Copy link
Contributor

Choose a reason for hiding this comment

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

The config file should probably require bldr_url be a Url, correct?

Copy link
Contributor Author

@jeremymv2 jeremymv2 Aug 12, 2020

Choose a reason for hiding this comment

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

The function now returns a Result<Url> type instead of String. Take a look and see if what's there now looks agreeable. 3568a83

components/hab/src/cli/hab/util.rs Outdated Show resolved Hide resolved
Comment on lines 9 to 13
pub const ORIGIN_MEMBER_ROLE_READONLY_MEMBER: &str = "readonly_member";
pub const ORIGIN_MEMBER_ROLE_MEMBER: &str = "member";
pub const ORIGIN_MEMBER_ROLE_MAINTAINER: &str = "maintainer";
pub const ORIGIN_MEMBER_ROLE_ADMINISTRATOR: &str = "administrator";
pub const ORIGIN_MEMBER_ROLE_OWNER: &str = "owner";
Copy link
Contributor

Choose a reason for hiding this comment

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

No need to change anything, but I am personally a fan of asciating constants like this with the type. So something like:

impl OriginMemberRole {
    const READONLY_MEMBER: &'static str = "readonly_member";
    const MEMBER: &'static str = "member";
    const MAINTAINER: &'static str = "maintainer";
    const ADMINISTRATOR: &'static str = "administrator";
    const OWNER: &'static str = "owner";
}

You can then access them with OriginMemberRole::READONLY_MEMBER

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Totally agree. Adjusted in 9aee65a

Copy link
Contributor

Choose a reason for hiding this comment

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

I like your change. Although, it was not quite what I had in mind 😄. My intention was to scope the constants within the OriginMemberRole so they should be defined in an impl OriginMemberRole { } block and accessed with OriginMemberRole::READONLY_MEMBER. But I dont think there is any need to change anything for this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ahh yes. I'll make it so.

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've modified in 78f9d5e

@jeremymv2
Copy link
Contributor Author

@davidMcneil I believe I've taken care of all the feedback items thus far. Care to sanity check me? ❤️

Comment on lines 266 to 267
/// The role name to enforce for the member account [values: readonly_member, member,
/// maintainer, administrator, owner]
Copy link
Contributor

Choose a reason for hiding this comment

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

We could use #[structopt(possible_values = &[OriginMemberRole::READONLY_MEMBER ...])] which will automatically display the possible values and has better traceability should we ever add an OriginMemberRole` variant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a nice capability. Added in 78f9d5e

Comment on lines 16 to 23
let res = tw.into_inner();
if res.is_err() {
return Err(Error::TabWriterIntoInnerFailed("Unable to flush \
tabwriter buffer to \
inner."
.to_string()));
}
let inner = res.unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

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

I dont think we should have a custom TabWriterIntoInnerFailed type. Instead we could use the io::Error that is part of tabwriter::IntoInnerError

We could use:

    let inner = tw.into_inner().map_err(|e| {
                                    IoError::new(e.error().kind(),
                                                 "Unable to flush tabwriter buffer to inner.")
                                })?;

This preserves the io::Error kind, prevents us from having to create a new type, and avoids an unwrap.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Modified as such in 78f9d5e

@@ -340,6 +347,7 @@ impl fmt::Display for Error {
Error::GetExitCodeProcessFailed(ref e) => e.to_string(),
Error::CreateToolhelp32SnapshotFailed(ref e) => e.to_string(),
Error::WaitForSingleObjectFailed(ref e) => e.to_string(),
Error::TabWriterIntoInnerFailed(ref e) => e.to_string(),
Copy link
Contributor

Choose a reason for hiding this comment

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

See other comments. I dont think this type should be needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed in 78f9d5e

@@ -48,6 +48,7 @@ pub enum Error {
HabitatCore(hcore::Error),
// Boxed due to clippy::large_enum_variant
HandlebarsRenderError(Box<handlebars::TemplateRenderError>),
InvalidUrl(String),
Copy link
Contributor

Choose a reason for hiding this comment

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

I dont think we should add this variant. See other comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Variant removed in 78f9d5e

Comment on lines 78 to 80
Url::parse(&bldr_url_from_env_load_or_default()).map_err(|e| {
Error::InvalidUrl(e.to_string())
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of mapping the error here, because this is the only possible error the function can return can we change the Error type the function returns?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed the error mapping in 78f9d5e

pub inner: Origin,
}

pub fn bldr_url_from_env_load_or_default() -> String {
Copy link
Contributor

Choose a reason for hiding this comment

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

This could be private.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to private in 78f9d5e

Comment on lines +88 to +99
match henv::var(AUTH_TOKEN_ENVVAR) {
Ok(v) => Ok(v),
Err(_) => {
config::load()?.auth_token.ok_or_else(|| {
Error::ArgumentError("No auth token specified. \
Please check that you have \
specified a valid Personal \
Access Token with: -z, \
--auth <AUTH_TOKEN>"
.into())
})
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this could use or_else

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 believe this has to be ok_or_else since config::load is returning an option for auth_token. If I change to or_else clippy says:

error[E0308]: mismatched types
  --> components/hab/src/cli/hab/util.rs:90:17
   |
83 |   pub fn bldr_auth_token_from_args_env_or_load(opt: Option<String>) -> Result<String, Error> {
   |                                                                        --------------------- expected `std::result::Result<std::string::String, error::Error>` because of return type
...
90 | /                 config::load()?.auth_token.or_else(|| {
91 | |                                               Error::ArgumentError("No auth token specified. \
92 | |                                                                     Please check that you have \
93 | |                                                                     specified a valid Personal \
...  |
96 | |                                                                                         .into())
97 | |                                           })
   | |____________________________________________^ expected enum `std::result::Result`, found enum `std::option::Option`
   |
   = note: expected enum `std::result::Result<std::string::String, error::Error>`
              found enum `std::option::Option<std::string::String>`

I need to return an result so that the CLI marshaling can error if no auth token is found and one is required. We need to figure out how to handle this natively in the future (loading from args, ENV, OR cli.toml. See: #7866

For now we need to return a Result so that we can error appropriately before calling the start function of the command:
let auth_token = bldr_auth_token_from_args_env_or_load(r.auth_token.value)?;

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, sorry I was not clear. I meant this part match henv::var(AUTH_TOKEN_ENVVAR) we could probably avoid the need to match on the Ok just to wrap it back up in Ok, but it would not really buy us that much.

}
} else {
ui.status(Status::Discovering, "origin member role".to_string())?;
println!("Member {} has the '{}' role in the {} origin.",
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this be a println? Maybe a ui.status or debug! instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added ui.status in 78f9d5e

Copy link
Contributor

@davidMcneil davidMcneil left a comment

Choose a reason for hiding this comment

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

Looks great, thanks!

@jeremymv2 jeremymv2 merged commit 020eb18 into master Aug 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type:Feature PRs that add a new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

hab cli subcommand for builder user role management
3 participants