Skip to content

Commit

Permalink
add service account create command (#324)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattkim authored Feb 2, 2024
1 parent 4d6f443 commit 69f7203
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 0 deletions.
91 changes: 91 additions & 0 deletions app/serviceaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,24 @@ func GetServiceAccountClient(ctx *cli.Context) (*ServiceAccountClient, error) {
}, nil
}

func (c *ServiceAccountClient) createServiceAccount(
ctx *cli.Context,
spec *auth.ServiceAccountSpec,
operationID string,
) error {
req := &authservice.CreateServiceAccountRequest{
Spec: spec,
AsyncOperationId: operationID,
}

resp, err := c.client.CreateServiceAccount(c.ctx, req)
if err != nil {
return fmt.Errorf("unable to create service account: %w", err)
}

return PrintProto(resp)
}

func (c *ServiceAccountClient) listServiceAccounts(
pageToken string,
pageSize int,
Expand Down Expand Up @@ -174,6 +192,79 @@ func NewServiceAccountCommand(getServiceAccountClientFn GetServiceAccountClientF
return err
},
Subcommands: []*cli.Command{
{
Name: "create",
Usage: "Create a service account",
Aliases: []string{"c"},
Flags: []cli.Flag{
serviceAccountDescriptionFlag,
serviceAccountNameFlag,
RequestIDFlag,
&cli.StringFlag{
Name: accountRoleFlagName,
Usage: fmt.Sprintf("The account role to set on the service account; valid types are: %v", accountActionGroups),
Required: true,
Aliases: []string{"ar"},
},
&cli.StringSliceFlag{
Name: namespacePermissionFlagName,
Usage: fmt.Sprintf("Flag can be used multiple times; value must be \"namespace=permission\"; valid types are: %v", namespaceActionGroups),
Aliases: []string{"np"},
},
},
Action: func(ctx *cli.Context) error {
if len(ctx.String(serviceAccountNameFlagName)) == 0 {
return fmt.Errorf("service account name must be provied with '--%s'", serviceAccountNameFlagName)
}

if len(ctx.String(accountRoleFlagName)) == 0 {
return fmt.Errorf("account role must be specified; valid types are %v", accountActionGroups)
}

if _, ok := auth.AccountActionGroup_value[ctx.String(accountRoleFlagName)]; !ok {
return fmt.Errorf("invalid account role; valid types are: %v", accountActionGroups)
}

spec := &auth.ServiceAccountSpec{
Name: ctx.String(serviceAccountNameFlagName),
Access: &identity.Access{
AccountAccess: &identity.AccountAccess{
Role: ctx.String(accountRoleFlagName),
},
NamespaceAccesses: map[string]*identity.NamespaceAccess{},
},
Description: ctx.String(serviceAccountDescriptionFlagName),
}

isAccountAdmin := ctx.String(accountRoleFlagName) == auth.AccountActionGroup_name[int32(auth.ACCOUNT_ACTION_GROUP_ADMIN)]
namespacePermissionsList := ctx.StringSlice(namespacePermissionFlagName)
if len(namespacePermissionsList) > 0 {
if isAccountAdmin {
y, err := ConfirmPrompt(ctx, "Setting admin role on service account. All existing namespace permissions will be replaced, please confirm")
if err != nil {
return err
}
if !y {
fmt.Println("operation canceled")
return nil
}
} else {
nsMap, err := toNamespacePermissionsMap(namespacePermissionsList)
if err != nil {
return fmt.Errorf("failed to read namespace permissions: %w", err)
}

for ns, perm := range nsMap {
spec.Access.NamespaceAccesses[ns] = &identity.NamespaceAccess{
Permission: perm,
}
}
}
}

return c.createServiceAccount(ctx, spec, ctx.String(RequestIDFlagName))
},
},
{
Name: "list",
Usage: "List service accounts",
Expand Down
23 changes: 23 additions & 0 deletions app/serviceaccount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,29 @@ func (s *ServiceAccountTestSuite) TestList() {
s.NoError(s.RunCmd("service-account", "list"))
}

func (s *ServiceAccountTestSuite) TestCreateServiceAccount() {
s.mockAuthService.EXPECT().CreateServiceAccount(gomock.Any(), gomock.Any()).Return(nil, errors.New("create service account error")).Times(1)
s.EqualError(s.RunCmd("service-account", "create", "--description", "test description", "--name", "test name", "--account-role", "Read"), "unable to create service account: create service account error")
s.mockAuthService.EXPECT().CreateServiceAccount(gomock.Any(), gomock.Any()).Return(&authservice.CreateServiceAccountResponse{
AsyncOperation: &operation.AsyncOperation{
State: "FULFILLED",
},
}, nil).Times(1)
s.NoError(s.RunCmd("service-account", "create", "--description", "test description", "--name", "test name", "--account-role", "Read"))
s.mockAuthService.EXPECT().CreateServiceAccount(gomock.Any(), gomock.Any()).Return(&authservice.CreateServiceAccountResponse{
AsyncOperation: &operation.AsyncOperation{
State: "FULFILLED",
},
}, nil).Times(1)
s.NoError(s.RunCmd("service-account", "create", "--description", "test description", "--name", "test name", "--account-role", "Admin", "--namespace-permission", "test-namespace=Admin"))
s.mockAuthService.EXPECT().CreateServiceAccount(gomock.Any(), gomock.Any()).Return(&authservice.CreateServiceAccountResponse{
AsyncOperation: &operation.AsyncOperation{
State: "FULFILLED",
},
}, nil).Times(1)
s.NoError(s.RunCmd("service-account", "create", "--description", "test description", "--name", "test name", "--account-role", "Read", "--namespace-permission", "test-namespace=Read"))
}

func (s *ServiceAccountTestSuite) TestDeleteServiceAccount() {
s.mockAuthService.EXPECT().GetServiceAccount(gomock.Any(), gomock.Any()).Return(nil, errors.New("get service account error")).Times(1)
s.EqualError(s.RunCmd("service-account", "delete", "--service-account-id", "test-service-account-id"), "unable to get service account: get service account error")
Expand Down

0 comments on commit 69f7203

Please sign in to comment.