-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
27 changed files
with
264 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package users | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/hashicorp/hcp-sdk-go/clients/cloud-iam/stable/2019-12-10/client/iam_service" | ||
"github.com/hashicorp/hcp/internal/pkg/cmd" | ||
"github.com/hashicorp/hcp/internal/pkg/heredoc" | ||
"github.com/hashicorp/hcp/internal/pkg/iostreams" | ||
"github.com/hashicorp/hcp/internal/pkg/profile" | ||
) | ||
|
||
func NewCmdDelete(ctx *cmd.Context, runF func(*DeleteOpts) error) *cmd.Command { | ||
opts := &DeleteOpts{ | ||
Ctx: ctx.ShutdownCtx, | ||
Profile: ctx.Profile, | ||
IO: ctx.IO, | ||
Client: iam_service.New(ctx.HCP, nil), | ||
} | ||
|
||
cmd := &cmd.Command{ | ||
Name: "delete", | ||
ShortHelp: "Delete a user from the organization.", | ||
LongHelp: heredoc.New(ctx.IO).Must(` | ||
The {{ Bold "hcp iam users delete" }} command deletes a user from the organization. | ||
`), | ||
Examples: []cmd.Example{ | ||
{ | ||
Preamble: `Delete a user`, | ||
Command: heredoc.New(ctx.IO, heredoc.WithPreserveNewlines()).Must(` | ||
$ hcp iam users delete example-id-123 | ||
`), | ||
}, | ||
}, | ||
Args: cmd.PositionalArguments{ | ||
Args: []cmd.PositionalArgument{ | ||
{ | ||
Name: "ID", | ||
Documentation: "The ID of the user to delete.", | ||
}, | ||
}, | ||
}, | ||
RunF: func(c *cmd.Command, args []string) error { | ||
opts.ID = args[0] | ||
if runF != nil { | ||
return runF(opts) | ||
} | ||
return deleteRun(opts) | ||
}, | ||
PersistentPreRun: func(c *cmd.Command, args []string) error { | ||
return cmd.RequireOrganization(ctx) | ||
}, | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
type DeleteOpts struct { | ||
Ctx context.Context | ||
IO iostreams.IOStreams | ||
Profile *profile.Profile | ||
|
||
ID string | ||
Client iam_service.ClientService | ||
} | ||
|
||
func deleteRun(opts *DeleteOpts) error { | ||
if opts.IO.CanPrompt() { | ||
ok, err := opts.IO.PromptConfirm("The user will be deleted from the organization.\n\nDo you want to continue") | ||
if err != nil { | ||
return fmt.Errorf("failed to retrieve confirmation: %w", err) | ||
} | ||
|
||
if !ok { | ||
return nil | ||
} | ||
} | ||
|
||
req := iam_service.NewIamServiceDeleteOrganizationMembershipParamsWithContext(opts.Ctx) | ||
req.OrganizationID = opts.Profile.OrganizationID | ||
req.UserPrincipalID = opts.ID | ||
|
||
_, err := opts.Client.IamServiceDeleteOrganizationMembership(req, nil) | ||
if err != nil { | ||
return fmt.Errorf("failed to delete user principal from organization: %w", err) | ||
} | ||
|
||
fmt.Fprintf(opts.IO.Err(), "%s User %q deleted from organization\n", | ||
opts.IO.ColorScheme().SuccessIcon(), opts.ID) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package users | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
"testing" | ||
|
||
"github.com/go-openapi/runtime/client" | ||
"github.com/hashicorp/hcp-sdk-go/clients/cloud-iam/stable/2019-12-10/client/iam_service" | ||
mock_iam_service "github.com/hashicorp/hcp/internal/pkg/api/mocks/github.com/hashicorp/hcp-sdk-go/clients/cloud-iam/stable/2019-12-10/client/iam_service" | ||
"github.com/hashicorp/hcp/internal/pkg/cmd" | ||
"github.com/hashicorp/hcp/internal/pkg/format" | ||
"github.com/hashicorp/hcp/internal/pkg/iostreams" | ||
"github.com/hashicorp/hcp/internal/pkg/profile" | ||
"github.com/stretchr/testify/mock" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestNewCmdDelete(t *testing.T) { | ||
t.Parallel() | ||
|
||
cases := []struct { | ||
Name string | ||
Args []string | ||
Profile func(t *testing.T) *profile.Profile | ||
Error string | ||
ExpectID string | ||
}{ | ||
{ | ||
Name: "No Org", | ||
Profile: profile.TestProfile, | ||
Args: []string{}, | ||
Error: "Organization ID must be configured before running the command.", | ||
}, | ||
{ | ||
Name: "Too many args", | ||
Profile: func(t *testing.T) *profile.Profile { | ||
return profile.TestProfile(t).SetOrgID("123").SetProjectID("456") | ||
}, | ||
Args: []string{"foo", "bar"}, | ||
Error: "accepts 1 arg(s), received 2", | ||
}, | ||
{ | ||
Name: "Good", | ||
Profile: func(t *testing.T) *profile.Profile { | ||
return profile.TestProfile(t).SetOrgID("123").SetProjectID("456") | ||
}, | ||
Args: []string{"foo"}, | ||
ExpectID: "foo", | ||
}, | ||
} | ||
|
||
for _, c := range cases { | ||
c := c | ||
t.Run(c.Name, func(t *testing.T) { | ||
t.Parallel() | ||
r := require.New(t) | ||
|
||
// Create a context. | ||
io := iostreams.Test() | ||
ctx := &cmd.Context{ | ||
IO: io, | ||
Profile: c.Profile(t), | ||
Output: format.New(io), | ||
HCP: &client.Runtime{}, | ||
ShutdownCtx: context.Background(), | ||
} | ||
|
||
var gotOpts *DeleteOpts | ||
readCmd := NewCmdDelete(ctx, func(o *DeleteOpts) error { | ||
gotOpts = o | ||
return nil | ||
}) | ||
readCmd.SetIO(io) | ||
|
||
code := readCmd.Run(c.Args) | ||
if c.Error != "" { | ||
r.NotZero(code) | ||
r.Contains(io.Error.String(), c.Error) | ||
return | ||
} | ||
|
||
r.Zero(code, io.Error.String()) | ||
r.NotNil(gotOpts) | ||
r.Equal(c.ExpectID, gotOpts.ID) | ||
}) | ||
} | ||
} | ||
|
||
func TestDeleteRun(t *testing.T) { | ||
t.Parallel() | ||
|
||
cases := []struct { | ||
Name string | ||
RespErr bool | ||
Error string | ||
}{ | ||
{ | ||
Name: "Server error", | ||
RespErr: true, | ||
Error: "failed to delete user principal from organization: [DELETE /iam/2019-12-10/organizations/{organization_id}/user-principals/{user_principal_id}][403]", | ||
}, | ||
{ | ||
Name: "Good", | ||
}, | ||
} | ||
|
||
for _, c := range cases { | ||
c := c | ||
t.Run(c.Name, func(t *testing.T) { | ||
t.Parallel() | ||
r := require.New(t) | ||
|
||
io := iostreams.Test() | ||
iam := mock_iam_service.NewMockClientService(t) | ||
opts := &DeleteOpts{ | ||
Ctx: context.Background(), | ||
Profile: profile.TestProfile(t).SetOrgID("123"), | ||
IO: io, | ||
Client: iam, | ||
ID: "456", | ||
} | ||
|
||
// Expect a request to get the user. | ||
call := iam.EXPECT().IamServiceDeleteOrganizationMembership(mock.MatchedBy(func(req *iam_service.IamServiceDeleteOrganizationMembershipParams) bool { | ||
return req.OrganizationID == "123" && req.UserPrincipalID == "456" | ||
}), nil).Once() | ||
|
||
if c.RespErr { | ||
call.Return(nil, iam_service.NewIamServiceDeleteOrganizationMembershipDefault(http.StatusForbidden)) | ||
} else { | ||
ok := iam_service.NewIamServiceDeleteOrganizationMembershipOK() | ||
call.Return(ok, nil) | ||
} | ||
|
||
// Run the command | ||
err := deleteRun(opts) | ||
if c.Error != "" { | ||
r.ErrorContains(err, c.Error) | ||
return | ||
} | ||
|
||
r.NoError(err) | ||
r.Contains(io.Error.String(), "User \"456\" deleted from organization") | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.