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
Add --teams flag to assign team name to stack. #11974
Conversation
I think I should test this with a mocked out HTTP client and inspect the request to ensure everything is wired together correctly. |
Changelog[uncommitted] (2023-03-21)Features
|
Also, |
c984453
to
ddaaba5
Compare
ddaaba5
to
a146d28
Compare
This PR adds a --teams flag to `pulumi stack init` which accepts a string. This flag can be provided multiple times. Each team that is provided is assigned read/write permissions on the stack after it has been initialized.
734a4c8
to
e7fccef
Compare
I've addressed all feedback on this PR, and I think it's ready to go. Looking for a final review/final feedback comments before we merge. The Service team has asked that we get this in urgently, as the end of the quarter is fast approaching. |
pkg/backend/backend.go
Outdated
type CreateStackOptions interface { | ||
// Teams returns the list of teams who should have access to | ||
// the newly created stack. This method is only approperate | ||
// for backends which support teams (i.e. the Service). | ||
Teams() []string | ||
} |
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.
Missed this discussion earlier in #11974 (comment) earlier.
Looking at the current version of the code:
I'm still not sure that the interface and the complexity its bringing buys us anything.
It doesn't actually give us make illegal states unrepresentable as suggested because there's only one real implementation that acts the same was as a plain CreateStackOptions struct would.
httpstate and filestate check the result of Teams()
the same way they would if it was a struct.
"Accept interfaces, return structs" is good advice for when the object has any behavior. These are just data objects with zero behavior.
I want to repeat my advise here on using a simple *CreateStackOptions
struct pointer argument.
That has a couple benefits. First, callers can safely pass in nil
when they don't care and the consumer of the options can just do if opts == nil { opts = &CreateStackOptions{}
, versus the current situation where callers either have to always pass a non-nil implementation or the consumer has to have a no-op implementation sitting around.
Second, and this is super minor, it avoids need of coming up with a second name for CreateStackOptions. (I find StandardCreateStackOptions to be a bit awkwardly named.)
// pkg/backend.go
type CreateStackOptions struct {
Teams []string
}
type Backend interface {
// ...
CreateStack(ctx context.Context, stackRef StackReference, root string, opts *CreateStackOptions) (Stack, error)
// ...
}
// pkg/filestate/backend.go
func (b *localBackend) CreateStack(ctx context.Context, stackRef backend.StackReference,
root string, opts *backend.CreateStackOptions,
) (backend.Stack, error) {
// Before locking the stack, validate that the options provided are valid.
if opts != nil && len(opts.Teams) > 0 {
return nil, &internalIllegalTeamsError{}
}
// pkg/httpstate/backend.go
func (b *cloudBackend) CreateStack(
ctx context.Context, stackRef backend.StackReference, root string,
opts *backend.CreateStackOptions,
) (
backend.Stack, error,
) {
if opts == nil {
opts = &backend.CreateStackOptions{}
}
// ...
apistack, err := b.client.CreateStack(ctx, stackID, tags, opts.Teams)
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 definitely disagree here. But instead of relitigating the merits, I'll make the change in a follow-on PR.
Since your objection isn't a matter of correctness and given that @justinvp has asked we get this feature in ASAP,
I'm afraid I have to insist we leave it as-is in this PR, but I'll open an issue and create a follow-on PR today to change the type from an interface into a struct.
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.
@RobbieMcKinstry
The tests are all still panicking with nil pointer dereferences.
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x284be1e]
goroutine 30 [running]:
testing.tRunner.func1.2({0x32d8680, 0x6f046a0})
/opt/hostedtoolcache/go/1.20.2/x64/src/testing/testing.go:1526 +0x372
testing.tRunner.func1()
/opt/hostedtoolcache/go/1.20.2/x64/src/testing/testing.go:1529 +0x650
panic({0x32d8680, 0x6f046a0})
/opt/hostedtoolcache/go/1.20.2/x64/src/runtime/panic.go:890 +0x263
github.com/pulumi/pulumi/pkg/v3/backend/httpstate.(*cloudBackend).CreateStack(0xc000938a80, {0x5be8a00, 0xc000136008}, {0x5be7d00, 0xc000f16bc0}, {0xc001b28c60, 0x17}, {0x0, 0x0})
/home/runner/work/pulumi/pulumi/pkg/backend/httpstate/backend.go:840 +0x1fe
The change I'm suggesting is trivial to make and will help address all of these panics.
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 agree with the feedback to use a simple struct here (*CreateStackOptions
). I'd expect it'd be a pretty quick change to make as part of this PR today. No need to do it as a follow-up.
Co-authored-by: Abhinav Gupta <abhinav@pulumi.com>
@RobbieMcKinstry Did you mean to push more code? The code for a lot of the comments marked resolved is unchanged. |
This commits addresses PR feedback to prefer using a contract assertion instead of returning an internal error. It also adds a test to validate how the --team flag is handled during stack creation when the backend doesn't support teams. Currently, the newly added test is expected to fail.
The previous iteration of the test failed, and I'm not sure why. This commit weakens the assertion, checking only for the presence of an Error, not inspecting the contents.
@abhinav I took one of your code comments -- a typo in |
I worked on addressing the comments locally and pushed a few commits to address. Going to look to see why CI is failing. |
Looks like another test elsewhere needs to be updated. On it. |
Per discussion, turn CreateStackOptions into a struct with a Teams field.
5667d72
to
093dab6
Compare
@abhinav that should be everything. |
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.
Looks fine to me
|
||
// TeamsUnsupportedError is the error returned when the --teams | ||
// flag is provided on a backend that doesn't support teams. | ||
type teamsUnsupportedError struct { |
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.
Not sure we really need an error struct for this? Not sure in general what our leaning is vis-a-vis making new error types or just using fmt.Errorf actually...
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.
Generally, we don't need to bother with new error types for short-enough messages,
where the caller doesn't need to match on that exact object and extract information
(relevant ref).
However, if the error message is complex/has a bunch of conditionals to determine what gets put in it,
an error object is worth.
In this case, we don't need it, but I don't consider it a blocker by any means.
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.
Let's discuss in ideation.
bors r+ |
Agh! Now the linter failed! |
Canceled. |
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.
LGTM
|
||
// TeamsUnsupportedError is the error returned when the --teams | ||
// flag is provided on a backend that doesn't support teams. | ||
type teamsUnsupportedError struct { |
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.
Generally, we don't need to bother with new error types for short-enough messages,
where the caller doesn't need to match on that exact object and extract information
(relevant ref).
However, if the error message is complex/has a bunch of conditionals to determine what gets put in it,
an error object is worth.
In this case, we don't need it, but I don't consider it a blocker by any means.
bors r+ |
Build succeeded:
|
This deletes the SupportsTeams method added in #11974. It came up during review that we want to avoid too many new "SupportsFoo" methods. Instead, we'll let each backend report whether it supports teams by returning ErrTeamsNotSupported. As a result of this change, validateCreateStackOpts cannot error, so it's been renamed to newCreateStackOptions. Testing: There's already a test (added in the #12499 refactor) that verifies that we report the appropriate error when the backend doesn't support --teams. This updates the mock in that test.
12551: pkg/backend: Delete SupportsTeams methods r=abhinav a=abhinav This deletes the SupportsTeams method added in #11974. It came up during review that we want to avoid too many new "SupportsFoo" methods. Instead, we'll let each backend report whether it supports teams by returning ErrTeamsNotSupported. As a result of this change, validateCreateStackOpts cannot error, so it's been renamed to newCreateStackOptions. Testing: There's already a test (added in the #12499 refactor) that verifies that we report the appropriate error when the backend doesn't support --teams. This updates the mock in that test. Co-authored-by: Abhinav Gupta <abhinav@pulumi.com>
Description
This PR adds a --teams flag to
pulumi stack init
which accepts a string. This flag can be provided multiple times. Each team that is provided is assigned read/write permissions on the stack after it has been initialized.Fixes #10784
Checklist
make changelog
and committed thechangelog/pending/<file>
documenting my change