Add API/CLI for managed groups (#1265)
This commit is contained in:
1 parent
179a49657e
commit
306d4fb4d3
42 files changed
+1481
-40
No files matched your search
@@ -0,0 +1,323 @@
|
||||
// Code generated by "make api"; DO NOT EDIT.
|
||||
package managedgroups
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/scopes"
|
||||
)
|
||||
|
||||
type ManagedGroup struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Scope *scopes.ScopeInfo `json:"scope,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
CreatedTime time.Time `json:"created_time,omitempty"`
|
||||
UpdatedTime time.Time `json:"updated_time,omitempty"`
|
||||
Version uint32 `json:"version,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
AuthMethodId string `json:"auth_method_id,omitempty"`
|
||||
Attributes map[string]interface{} `json:"attributes,omitempty"`
|
||||
MemberIds []string `json:"member_ids,omitempty"`
|
||||
AuthorizedActions []string `json:"authorized_actions,omitempty"`
|
||||
|
||||
response *api.Response
|
||||
}
|
||||
|
||||
type ManagedGroupReadResult struct {
|
||||
Item *ManagedGroup
|
||||
response *api.Response
|
||||
}
|
||||
|
||||
func (n ManagedGroupReadResult) GetItem() interface{} {
|
||||
return n.Item
|
||||
}
|
||||
|
||||
func (n ManagedGroupReadResult) GetResponse() *api.Response {
|
||||
return n.response
|
||||
}
|
||||
|
||||
type (
|
||||
ManagedGroupCreateResult = ManagedGroupReadResult
|
||||
ManagedGroupUpdateResult = ManagedGroupReadResult
|
||||
)
|
||||
|
||||
type ManagedGroupDeleteResult struct {
|
||||
response *api.Response
|
||||
}
|
||||
|
||||
// GetItem will always be nil for ManagedGroupDeleteResult
|
||||
func (n ManagedGroupDeleteResult) GetItem() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n ManagedGroupDeleteResult) GetResponse() *api.Response {
|
||||
return n.response
|
||||
}
|
||||
|
||||
type ManagedGroupListResult struct {
|
||||
Items []*ManagedGroup
|
||||
response *api.Response
|
||||
}
|
||||
|
||||
func (n ManagedGroupListResult) GetItems() interface{} {
|
||||
return n.Items
|
||||
}
|
||||
|
||||
func (n ManagedGroupListResult) GetResponse() *api.Response {
|
||||
return n.response
|
||||
}
|
||||
|
||||
// Client is a client for this collection
|
||||
type Client struct {
|
||||
client *api.Client
|
||||
}
|
||||
|
||||
// Creates a new client for this collection. The submitted API client is cloned;
|
||||
// modifications to it after generating this client will not have effect. If you
|
||||
// need to make changes to the underlying API client, use ApiClient() to access
|
||||
// it.
|
||||
func NewClient(c *api.Client) *Client {
|
||||
return &Client{client: c.Clone()}
|
||||
}
|
||||
|
||||
// ApiClient returns the underlying API client
|
||||
func (c *Client) ApiClient() *api.Client {
|
||||
return c.client
|
||||
}
|
||||
|
||||
func (c *Client) Create(ctx context.Context, authMethodId string, opt ...Option) (*ManagedGroupCreateResult, error) {
|
||||
if authMethodId == "" {
|
||||
return nil, fmt.Errorf("empty authMethodId value passed into Create request")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
|
||||
opts.postMap["auth_method_id"] = authMethodId
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "POST", "managed-groups", opts.postMap, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Create request: %w", err)
|
||||
}
|
||||
|
||||
if len(opts.queryMap) > 0 {
|
||||
q := url.Values{}
|
||||
for k, v := range opts.queryMap {
|
||||
q.Add(k, v)
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error performing client request during Create call: %w", err)
|
||||
}
|
||||
|
||||
target := new(ManagedGroupCreateResult)
|
||||
target.Item = new(ManagedGroup)
|
||||
apiErr, err := resp.Decode(target.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding Create response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
target.response = resp
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (c *Client) Read(ctx context.Context, managedGroupId string, opt ...Option) (*ManagedGroupReadResult, error) {
|
||||
if managedGroupId == "" {
|
||||
return nil, fmt.Errorf("empty managedGroupId value passed into Read request")
|
||||
}
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "GET", fmt.Sprintf("managed-groups/%s", managedGroupId), nil, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Read request: %w", err)
|
||||
}
|
||||
|
||||
if len(opts.queryMap) > 0 {
|
||||
q := url.Values{}
|
||||
for k, v := range opts.queryMap {
|
||||
q.Add(k, v)
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error performing client request during Read call: %w", err)
|
||||
}
|
||||
|
||||
target := new(ManagedGroupReadResult)
|
||||
target.Item = new(ManagedGroup)
|
||||
apiErr, err := resp.Decode(target.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding Read response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
target.response = resp
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (c *Client) Update(ctx context.Context, managedGroupId string, version uint32, opt ...Option) (*ManagedGroupUpdateResult, error) {
|
||||
if managedGroupId == "" {
|
||||
return nil, fmt.Errorf("empty managedGroupId value passed into Update request")
|
||||
}
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
|
||||
if version == 0 {
|
||||
if !opts.withAutomaticVersioning {
|
||||
return nil, errors.New("zero version number passed into Update request and automatic versioning not specified")
|
||||
}
|
||||
existingTarget, existingErr := c.Read(ctx, managedGroupId, append([]Option{WithSkipCurlOutput(true)}, opt...)...)
|
||||
if existingErr != nil {
|
||||
if api.AsServerError(existingErr) != nil {
|
||||
return nil, fmt.Errorf("error from controller when performing initial check-and-set read: %w", existingErr)
|
||||
}
|
||||
return nil, fmt.Errorf("error performing initial check-and-set read: %w", existingErr)
|
||||
}
|
||||
if existingTarget == nil {
|
||||
return nil, errors.New("nil resource response found when performing initial check-and-set read")
|
||||
}
|
||||
if existingTarget.Item == nil {
|
||||
return nil, errors.New("nil resource found when performing initial check-and-set read")
|
||||
}
|
||||
version = existingTarget.Item.Version
|
||||
}
|
||||
|
||||
opts.postMap["version"] = version
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "PATCH", fmt.Sprintf("managed-groups/%s", managedGroupId), opts.postMap, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Update request: %w", err)
|
||||
}
|
||||
|
||||
if len(opts.queryMap) > 0 {
|
||||
q := url.Values{}
|
||||
for k, v := range opts.queryMap {
|
||||
q.Add(k, v)
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error performing client request during Update call: %w", err)
|
||||
}
|
||||
|
||||
target := new(ManagedGroupUpdateResult)
|
||||
target.Item = new(ManagedGroup)
|
||||
apiErr, err := resp.Decode(target.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding Update response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
target.response = resp
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (c *Client) Delete(ctx context.Context, managedGroupId string, opt ...Option) (*ManagedGroupDeleteResult, error) {
|
||||
if managedGroupId == "" {
|
||||
return nil, fmt.Errorf("empty managedGroupId value passed into Delete request")
|
||||
}
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("managed-groups/%s", managedGroupId), nil, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating Delete request: %w", err)
|
||||
}
|
||||
|
||||
if len(opts.queryMap) > 0 {
|
||||
q := url.Values{}
|
||||
for k, v := range opts.queryMap {
|
||||
q.Add(k, v)
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error performing client request during Delete call: %w", err)
|
||||
}
|
||||
|
||||
apiErr, err := resp.Decode(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding Delete response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
|
||||
target := &ManagedGroupDeleteResult{
|
||||
response: resp,
|
||||
}
|
||||
return target, nil
|
||||
}
|
||||
|
||||
func (c *Client) List(ctx context.Context, authMethodId string, opt ...Option) (*ManagedGroupListResult, error) {
|
||||
if authMethodId == "" {
|
||||
return nil, fmt.Errorf("empty authMethodId value passed into List request")
|
||||
}
|
||||
if c.client == nil {
|
||||
return nil, fmt.Errorf("nil client")
|
||||
}
|
||||
|
||||
opts, apiOpts := getOpts(opt...)
|
||||
opts.queryMap["auth_method_id"] = authMethodId
|
||||
|
||||
req, err := c.client.NewRequest(ctx, "GET", "managed-groups", nil, apiOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error creating List request: %w", err)
|
||||
}
|
||||
|
||||
if len(opts.queryMap) > 0 {
|
||||
q := url.Values{}
|
||||
for k, v := range opts.queryMap {
|
||||
q.Add(k, v)
|
||||
}
|
||||
req.URL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error performing client request during List call: %w", err)
|
||||
}
|
||||
|
||||
target := new(ManagedGroupListResult)
|
||||
apiErr, err := resp.Decode(target)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error decoding List response: %w", err)
|
||||
}
|
||||
if apiErr != nil {
|
||||
return nil, apiErr
|
||||
}
|
||||
target.response = resp
|
||||
return target, nil
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// Code generated by "make api"; DO NOT EDIT.
|
||||
package managedgroups
|
||||
|
||||
type OidcManagedGroupAttributes struct {
|
||||
Filter string `json:"filter,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
package managedgroups
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
)
|
||||
|
||||
// Option is a func that sets optional attributes for a call. This does not need
|
||||
// to be used directly, but instead option arguments are built from the
|
||||
// functions in this package. WithX options set a value to that given in the
|
||||
// argument; DefaultX options indicate that the value should be set to its
|
||||
// default. When an API call is made options are processed in ther order they
|
||||
// appear in the function call, so for a given argument X, a succession of WithX
|
||||
// or DefaultX calls will result in the last call taking effect.
|
||||
type Option func(*options)
|
||||
|
||||
type options struct {
|
||||
postMap map[string]interface{}
|
||||
queryMap map[string]string
|
||||
withAutomaticVersioning bool
|
||||
withSkipCurlOutput bool
|
||||
withFilter string
|
||||
}
|
||||
|
||||
func getDefaultOptions() options {
|
||||
return options{
|
||||
postMap: make(map[string]interface{}),
|
||||
queryMap: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func getOpts(opt ...Option) (options, []api.Option) {
|
||||
opts := getDefaultOptions()
|
||||
for _, o := range opt {
|
||||
if o != nil {
|
||||
o(&opts)
|
||||
}
|
||||
}
|
||||
var apiOpts []api.Option
|
||||
if opts.withSkipCurlOutput {
|
||||
apiOpts = append(apiOpts, api.WithSkipCurlOutput(true))
|
||||
}
|
||||
if opts.withFilter != "" {
|
||||
opts.queryMap["filter"] = opts.withFilter
|
||||
}
|
||||
return opts, apiOpts
|
||||
}
|
||||
|
||||
// If set, and if the version is zero during an update, the API will perform a
|
||||
// fetch to get the current version of the resource and populate it during the
|
||||
// update call. This is convenient but opens up the possibility for subtle
|
||||
// order-of-modification issues, so use carefully.
|
||||
func WithAutomaticVersioning(enable bool) Option {
|
||||
return func(o *options) {
|
||||
o.withAutomaticVersioning = enable
|
||||
}
|
||||
}
|
||||
|
||||
// WithSkipCurlOutput tells the API to not use the current call for cURL output.
|
||||
// Useful for when we need to look up versions.
|
||||
func WithSkipCurlOutput(skip bool) Option {
|
||||
return func(o *options) {
|
||||
o.withSkipCurlOutput = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithFilter tells the API to filter the items returned using the provided
|
||||
// filter term. The filter should be in a format supported by
|
||||
// hashicorp/go-bexpr.
|
||||
func WithFilter(filter string) Option {
|
||||
return func(o *options) {
|
||||
o.withFilter = strings.TrimSpace(filter)
|
||||
}
|
||||
}
|
||||
|
||||
func WithAttributes(inAttributes map[string]interface{}) Option {
|
||||
return func(o *options) {
|
||||
o.postMap["attributes"] = inAttributes
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultAttributes() Option {
|
||||
return func(o *options) {
|
||||
o.postMap["attributes"] = nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithDescription(inDescription string) Option {
|
||||
return func(o *options) {
|
||||
o.postMap["description"] = inDescription
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultDescription() Option {
|
||||
return func(o *options) {
|
||||
o.postMap["description"] = nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithOidcManagedGroupFilter(inFilter string) Option {
|
||||
return func(o *options) {
|
||||
raw, ok := o.postMap["attributes"]
|
||||
if !ok {
|
||||
raw = interface{}(map[string]interface{}{})
|
||||
}
|
||||
val := raw.(map[string]interface{})
|
||||
val["filter"] = inFilter
|
||||
o.postMap["attributes"] = val
|
||||
}
|
||||
}
|
||||
|
||||
func WithName(inName string) Option {
|
||||
return func(o *options) {
|
||||
o.postMap["name"] = inName
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultName() Option {
|
||||
return func(o *options) {
|
||||
o.postMap["name"] = nil
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/hostcatalogs"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/hosts"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/hostsets"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/managedgroups"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/roles"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/scopes"
|
||||
"github.com/hashicorp/boundary/internal/gen/controller/api/resources/sessions"
|
||||
@@ -87,6 +88,10 @@ type structInfo struct {
|
||||
// conveyed within the item itself
|
||||
extraOptions []fieldInfo
|
||||
|
||||
// fieldOverrides allows overriding some field behavior without making them
|
||||
// "new" fields like with extraOptions
|
||||
fieldOverrides []fieldInfo
|
||||
|
||||
// createResponseTypes controls for which structs response types are created
|
||||
createResponseTypes bool
|
||||
|
||||
@@ -298,6 +303,34 @@ var inputStructs = []*structInfo{
|
||||
versionEnabled: true,
|
||||
createResponseTypes: true,
|
||||
},
|
||||
// Managed Groups
|
||||
{
|
||||
inProto: &managedgroups.OidcManagedGroupAttributes{},
|
||||
outFile: "managedgroups/oidc_managed_group_attributes.gen.go",
|
||||
subtypeName: "OidcManagedGroup",
|
||||
fieldOverrides: []fieldInfo{
|
||||
{
|
||||
Name: "Filter",
|
||||
SkipDefault: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
inProto: &managedgroups.ManagedGroup{},
|
||||
outFile: "managedgroups/managedgroups.gen.go",
|
||||
templates: []*template.Template{
|
||||
clientTemplate,
|
||||
createTemplate,
|
||||
readTemplate,
|
||||
updateTemplate,
|
||||
deleteTemplate,
|
||||
listTemplate,
|
||||
},
|
||||
pathArgs: []string{"managed-group"},
|
||||
parentTypeName: "auth-method",
|
||||
versionEnabled: true,
|
||||
createResponseTypes: true,
|
||||
},
|
||||
// Auth Tokens
|
||||
{
|
||||
inProto: &authtokens.AuthToken{},
|
||||
|
||||
@@ -123,6 +123,19 @@ func fillTemplates() {
|
||||
}
|
||||
optionsMap[input.Package] = optionMap
|
||||
}
|
||||
// Override some defined options
|
||||
if len(in.fieldOverrides) > 0 && optionsMap != nil {
|
||||
for _, override := range in.fieldOverrides {
|
||||
inOpts := optionsMap[input.Package]
|
||||
if inOpts != nil {
|
||||
if override.SkipDefault {
|
||||
fieldInfo := inOpts[override.Name]
|
||||
fieldInfo.SkipDefault = true
|
||||
inOpts[override.Name] = fieldInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outFile, err := filepath.Abs(fmt.Sprintf("%s/%s", os.Getenv("API_GEN_BASEPATH"), in.outFile))
|
||||
if err != nil {
|
||||
|
||||
@@ -214,3 +214,28 @@ func (r *Repository) ListManagedGroupMembershipsByMember(ctx context.Context, wi
|
||||
}
|
||||
return mgs, nil
|
||||
}
|
||||
|
||||
// ListManagedGroupMembershipsByGroup lists managed group memberships via the
|
||||
// group ID and supports WithLimit option.
|
||||
func (r *Repository) ListManagedGroupMembershipsByGroup(ctx context.Context, withGroupId string, opt ...Option) ([]*ManagedGroupMemberAccount, error) {
|
||||
const op = "oidc.(Repository).ListManagedGroupMembershipsByGroup"
|
||||
if withGroupId == "" {
|
||||
return nil, errors.New(errors.InvalidParameter, op, "missing managed group id")
|
||||
}
|
||||
opts := getOpts(opt...)
|
||||
limit := r.defaultLimit
|
||||
if opts.withLimit != 0 {
|
||||
// non-zero signals an override of the default limit for the repo.
|
||||
limit = opts.withLimit
|
||||
}
|
||||
reader := r.reader
|
||||
if opts.withReader != nil {
|
||||
reader = opts.withReader
|
||||
}
|
||||
var mgs []*ManagedGroupMemberAccount
|
||||
err := reader.SearchWhere(ctx, &mgs, "managed_group_id = ?", []interface{}{withGroupId}, db.WithLimit(limit))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, op)
|
||||
}
|
||||
return mgs, nil
|
||||
}
|
||||
@@ -258,6 +258,18 @@ func Test_ManagedGroupMemberships(t *testing.T) {
|
||||
// been in the finalMgs map, and when they are all removed there
|
||||
// should be nothing left.
|
||||
for _, mship := range memberships {
|
||||
// Randomly check a few to ensure the MembershipsByGroup function works
|
||||
members, err := repo.ListManagedGroupMembershipsByGroup(ctx, mship.ManagedGroupId)
|
||||
require.NoError(err)
|
||||
require.NotEmpty(members)
|
||||
var found bool
|
||||
for _, v := range members {
|
||||
if v.MemberId == tt.account.GetPublicId() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(found)
|
||||
assert.Contains(finalMgs, mship.ManagedGroupId)
|
||||
delete(finalMgs, mship.ManagedGroupId)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/hostscmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/hostsetscmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/logout"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/managedgroupscmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/rolescmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/scopescmd"
|
||||
"github.com/hashicorp/boundary/internal/cmd/commands/server"
|
||||
@@ -546,6 +547,54 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
|
||||
}, nil
|
||||
},
|
||||
|
||||
"managed-groups": func() (cli.Command, error) {
|
||||
return &managedgroupscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
}, nil
|
||||
},
|
||||
"managed-groups read": func() (cli.Command, error) {
|
||||
return &managedgroupscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "read",
|
||||
}, nil
|
||||
},
|
||||
"managed-groups delete": func() (cli.Command, error) {
|
||||
return &managedgroupscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "delete",
|
||||
}, nil
|
||||
},
|
||||
"managed-groups list": func() (cli.Command, error) {
|
||||
return &managedgroupscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "list",
|
||||
}, nil
|
||||
},
|
||||
"managed-groups create": func() (cli.Command, error) {
|
||||
return &managedgroupscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "create",
|
||||
}, nil
|
||||
},
|
||||
"managed-groups create oidc": func() (cli.Command, error) {
|
||||
return &managedgroupscmd.OidcCommand{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "create",
|
||||
}, nil
|
||||
},
|
||||
"managed-groups update": func() (cli.Command, error) {
|
||||
return &managedgroupscmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "update",
|
||||
}, nil
|
||||
},
|
||||
"managed-groups update oidc": func() (cli.Command, error) {
|
||||
return &managedgroupscmd.OidcCommand{
|
||||
Command: base.NewCommand(ui),
|
||||
Func: "update",
|
||||
}, nil
|
||||
},
|
||||
|
||||
"roles": func() (cli.Command, error) {
|
||||
return &rolescmd.Command{
|
||||
Command: base.NewCommand(ui),
|
||||
|
||||
@@ -103,7 +103,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "account", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "account", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ func (c *OidcCommand) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "oidc-type account", flagsOidcMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "oidc-type account", flagsOidcMap, c.Func)
|
||||
|
||||
extraOidcFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ func (c *PasswordCommand) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "password-type account", flagsPasswordMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "password-type account", flagsPasswordMap, c.Func)
|
||||
|
||||
extraPasswordFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "auth method", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "auth method", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ func (c *OidcCommand) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "oidc-type auth method", flagsOidcMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "oidc-type auth method", flagsOidcMap, c.Func)
|
||||
|
||||
extraOidcFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ func (c *PasswordCommand) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "password-type auth method", flagsPasswordMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "password-type auth method", flagsPasswordMap, c.Func)
|
||||
|
||||
extraPasswordFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "auth token", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "auth token", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "group", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "group", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "host catalog", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "host catalog", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ func (c *StaticCommand) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "static-type host catalog", flagsStaticMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "static-type host catalog", flagsStaticMap, c.Func)
|
||||
|
||||
extraStaticFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "host", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "host", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ func (c *StaticCommand) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "static-type host", flagsStaticMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "static-type host", flagsStaticMap, c.Func)
|
||||
|
||||
extraStaticFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "host set", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "host set", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ func (c *StaticCommand) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "static-type host set", flagsStaticMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "static-type host set", flagsStaticMap, c.Func)
|
||||
|
||||
extraStaticFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
package managedgroupscmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/managedgroups"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
)
|
||||
|
||||
func (c *Command) printListTable(items []*managedgroups.ManagedGroup) string {
|
||||
if len(items) == 0 {
|
||||
return "No managed groups found"
|
||||
}
|
||||
var output []string
|
||||
output = []string{
|
||||
"",
|
||||
"Managed Group information:",
|
||||
}
|
||||
for i, item := range items {
|
||||
if i > 0 {
|
||||
output = append(output, "")
|
||||
}
|
||||
if item.Id != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" ID: %s", item.Id),
|
||||
)
|
||||
} else {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" ID: %s", "(not available)"),
|
||||
)
|
||||
}
|
||||
if item.Version > 0 {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Version: %d", item.Version),
|
||||
)
|
||||
}
|
||||
if item.Type != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Type: %s", item.Type),
|
||||
)
|
||||
}
|
||||
if item.Name != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Name: %s", item.Name),
|
||||
)
|
||||
}
|
||||
if item.Description != "" {
|
||||
output = append(output,
|
||||
fmt.Sprintf(" Description: %s", item.Description),
|
||||
)
|
||||
}
|
||||
if len(item.AuthorizedActions) > 0 {
|
||||
output = append(output,
|
||||
" Authorized Actions:",
|
||||
base.WrapSlice(6, item.AuthorizedActions),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return base.WrapForHelpText(output)
|
||||
}
|
||||
|
||||
func printItemTable(result api.GenericResult) string {
|
||||
item := result.GetItem().(*managedgroups.ManagedGroup)
|
||||
nonAttributeMap := map[string]interface{}{}
|
||||
if item.Id != "" {
|
||||
nonAttributeMap["ID"] = item.Id
|
||||
}
|
||||
if item.Version != 0 {
|
||||
nonAttributeMap["Version"] = item.Version
|
||||
}
|
||||
if item.Type != "" {
|
||||
nonAttributeMap["Type"] = item.Type
|
||||
}
|
||||
if !item.CreatedTime.IsZero() {
|
||||
nonAttributeMap["Created Time"] = item.CreatedTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if !item.UpdatedTime.IsZero() {
|
||||
nonAttributeMap["Updated Time"] = item.UpdatedTime.Local().Format(time.RFC1123)
|
||||
}
|
||||
if item.AuthMethodId != "" {
|
||||
nonAttributeMap["Auth Method ID"] = item.AuthMethodId
|
||||
}
|
||||
if item.Name != "" {
|
||||
nonAttributeMap["Name"] = item.Name
|
||||
}
|
||||
if item.Description != "" {
|
||||
nonAttributeMap["Description"] = item.Description
|
||||
}
|
||||
|
||||
maxLength := base.MaxAttributesLength(nonAttributeMap, item.Attributes, keySubstMap)
|
||||
|
||||
ret := []string{
|
||||
"",
|
||||
"Managed Group information:",
|
||||
base.WrapMap(2, maxLength+2, nonAttributeMap),
|
||||
}
|
||||
|
||||
if item.Scope != nil {
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Scope:",
|
||||
base.ScopeInfoForOutput(item.Scope, maxLength),
|
||||
)
|
||||
}
|
||||
|
||||
if len(item.AuthorizedActions) > 0 {
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Authorized Actions:",
|
||||
base.WrapSlice(4, item.AuthorizedActions),
|
||||
)
|
||||
}
|
||||
|
||||
if len(item.MemberIds) > 0 {
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Member IDs:",
|
||||
base.WrapSlice(4, item.MemberIds),
|
||||
)
|
||||
}
|
||||
|
||||
if len(item.Attributes) > 0 {
|
||||
ret = append(ret,
|
||||
"",
|
||||
" Attributes:",
|
||||
base.WrapMap(4, maxLength, item.Attributes),
|
||||
)
|
||||
}
|
||||
|
||||
return base.WrapForHelpText(ret)
|
||||
}
|
||||
|
||||
var keySubstMap = map[string]string{
|
||||
"filter": "Filter",
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
// Code generated by "make api"; DO NOT EDIT.
|
||||
package managedgroupscmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/managedgroups"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/common"
|
||||
"github.com/hashicorp/boundary/sdk/strutil"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
||||
func initFlags() {
|
||||
flagsOnce.Do(func() {
|
||||
extraFlags := extraActionsFlagsMapFunc()
|
||||
for k, v := range extraFlags {
|
||||
flagsMap[k] = append(flagsMap[k], v...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
_ cli.Command = (*Command)(nil)
|
||||
_ cli.CommandAutocomplete = (*Command)(nil)
|
||||
)
|
||||
|
||||
type Command struct {
|
||||
*base.Command
|
||||
|
||||
Func string
|
||||
|
||||
plural string
|
||||
}
|
||||
|
||||
func (c *Command) AutocompleteArgs() complete.Predictor {
|
||||
initFlags()
|
||||
return complete.PredictAnything
|
||||
}
|
||||
|
||||
func (c *Command) AutocompleteFlags() complete.Flags {
|
||||
initFlags()
|
||||
return c.Flags().Completions()
|
||||
}
|
||||
|
||||
func (c *Command) Synopsis() string {
|
||||
if extra := extraSynopsisFunc(c); extra != "" {
|
||||
return extra
|
||||
}
|
||||
|
||||
synopsisStr := "managed group"
|
||||
|
||||
return common.SynopsisFunc(c.Func, synopsisStr)
|
||||
}
|
||||
|
||||
func (c *Command) Help() string {
|
||||
initFlags()
|
||||
|
||||
var helpStr string
|
||||
helpMap := common.HelpMap("managed group")
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "read":
|
||||
helpStr = helpMap[c.Func]() + c.Flags().Help()
|
||||
|
||||
case "delete":
|
||||
helpStr = helpMap[c.Func]() + c.Flags().Help()
|
||||
|
||||
case "list":
|
||||
helpStr = helpMap[c.Func]() + c.Flags().Help()
|
||||
|
||||
default:
|
||||
|
||||
helpStr = helpMap["base"]()
|
||||
|
||||
}
|
||||
|
||||
// Keep linter from complaining if we don't actually generate code using it
|
||||
_ = helpMap
|
||||
return helpStr
|
||||
}
|
||||
|
||||
var flagsMap = map[string][]string{
|
||||
|
||||
"read": {"id"},
|
||||
|
||||
"delete": {"id"},
|
||||
|
||||
"list": {"auth-method-id", "filter"},
|
||||
}
|
||||
|
||||
func (c *Command) Flags() *base.FlagSets {
|
||||
if len(flagsMap[c.Func]) == 0 {
|
||||
return c.FlagSet(base.FlagSetNone)
|
||||
}
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "managed group", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *Command) Run(args []string) int {
|
||||
initFlags()
|
||||
|
||||
switch c.Func {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
|
||||
case "create", "update":
|
||||
return cli.RunResultHelp
|
||||
|
||||
}
|
||||
|
||||
c.plural = "managed group"
|
||||
switch c.Func {
|
||||
case "list":
|
||||
c.plural = "managed groups"
|
||||
}
|
||||
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
if strutil.StrListContains(flagsMap[c.Func], "id") && c.FlagId == "" {
|
||||
c.PrintCliError(errors.New("ID is required but not passed in via -id"))
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
var opts []managedgroups.Option
|
||||
|
||||
if strutil.StrListContains(flagsMap[c.Func], "auth-method-id") {
|
||||
switch c.Func {
|
||||
case "list":
|
||||
if c.FlagAuthMethodId == "" {
|
||||
c.PrintCliError(errors.New("AuthMethod ID must be passed in via -auth-method-id or BOUNDARY_AUTH_METHOD_ID"))
|
||||
return base.CommandUserError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client, err := c.Client()
|
||||
if err != nil {
|
||||
c.PrintCliError(fmt.Errorf("Error creating API client: %s", err.Error()))
|
||||
return base.CommandCliError
|
||||
}
|
||||
managedgroupsClient := managedgroups.NewClient(client)
|
||||
|
||||
switch c.FlagName {
|
||||
case "":
|
||||
case "null":
|
||||
opts = append(opts, managedgroups.DefaultName())
|
||||
default:
|
||||
opts = append(opts, managedgroups.WithName(c.FlagName))
|
||||
}
|
||||
|
||||
switch c.FlagDescription {
|
||||
case "":
|
||||
case "null":
|
||||
opts = append(opts, managedgroups.DefaultDescription())
|
||||
default:
|
||||
opts = append(opts, managedgroups.WithDescription(c.FlagDescription))
|
||||
}
|
||||
|
||||
if c.FlagFilter != "" {
|
||||
opts = append(opts, managedgroups.WithFilter(c.FlagFilter))
|
||||
}
|
||||
|
||||
var version uint32
|
||||
|
||||
if ok := extraFlagsHandlingFunc(c, f, &opts); !ok {
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
var result api.GenericResult
|
||||
|
||||
var listResult api.GenericListResult
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "read":
|
||||
result, err = managedgroupsClient.Read(c.Context, c.FlagId, opts...)
|
||||
|
||||
case "delete":
|
||||
result, err = managedgroupsClient.Delete(c.Context, c.FlagId, opts...)
|
||||
|
||||
case "list":
|
||||
listResult, err = managedgroupsClient.List(c.Context, c.FlagAuthMethodId, opts...)
|
||||
|
||||
}
|
||||
|
||||
result, err = executeExtraActions(c, result, err, managedgroupsClient, version, opts)
|
||||
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil {
|
||||
c.PrintApiError(apiErr, fmt.Sprintf("Error from controller when performing %s on %s", c.Func, c.plural))
|
||||
return base.CommandApiError
|
||||
}
|
||||
c.PrintCliError(fmt.Errorf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
output, err := printCustomActionOutput(c)
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
if output {
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "delete":
|
||||
switch base.Format(c.UI) {
|
||||
case "json":
|
||||
if ok := c.PrintJsonItem(result); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
case "table":
|
||||
c.UI.Output("The delete operation completed successfully.")
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
|
||||
case "list":
|
||||
switch base.Format(c.UI) {
|
||||
case "json":
|
||||
if ok := c.PrintJsonItems(listResult); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
case "table":
|
||||
listedItems := listResult.GetItems().([]*managedgroups.ManagedGroup)
|
||||
c.UI.Output(c.printListTable(listedItems))
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
|
||||
}
|
||||
|
||||
switch base.Format(c.UI) {
|
||||
case "table":
|
||||
c.UI.Output(printItemTable(result))
|
||||
|
||||
case "json":
|
||||
if ok := c.PrintJsonItem(result); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
var (
|
||||
flagsOnce = new(sync.Once)
|
||||
|
||||
extraActionsFlagsMapFunc = func() map[string][]string { return nil }
|
||||
extraSynopsisFunc = func(*Command) string { return "" }
|
||||
extraFlagsFunc = func(*Command, *base.FlagSets, *base.FlagSet) {}
|
||||
extraFlagsHandlingFunc = func(*Command, *base.FlagSets, *[]managedgroups.Option) bool { return true }
|
||||
executeExtraActions = func(_ *Command, inResult api.GenericResult, inErr error, _ *managedgroups.Client, _ uint32, _ []managedgroups.Option) (api.GenericResult, error) {
|
||||
return inResult, inErr
|
||||
}
|
||||
printCustomActionOutput = func(*Command) (bool, error) { return false, nil }
|
||||
)
|
||||
@@ -0,0 +1,95 @@
|
||||
package managedgroupscmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/api/managedgroups"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/go-bexpr"
|
||||
)
|
||||
|
||||
const (
|
||||
filterFlagName = "filter"
|
||||
)
|
||||
|
||||
func init() {
|
||||
extraOidcFlagsFunc = extraOidcFlagsFuncImpl
|
||||
extraOidcActionsFlagsMapFunc = extraOidcActionsFlagsMapFuncImpl
|
||||
extraOidcFlagsHandlingFunc = extraOidcFlagsHandlingFuncImpl
|
||||
}
|
||||
|
||||
func extraOidcActionsFlagsMapFuncImpl() map[string][]string {
|
||||
return map[string][]string{
|
||||
"create": {filterFlagName},
|
||||
"update": {filterFlagName},
|
||||
}
|
||||
}
|
||||
|
||||
type extraOidcCmdVars struct {
|
||||
flagFilter string
|
||||
}
|
||||
|
||||
func (c *OidcCommand) extraOidcHelpFunc(helpMap map[string]func() string) string {
|
||||
var helpStr string
|
||||
switch c.Func {
|
||||
case "create":
|
||||
helpStr = base.WrapForHelpText([]string{
|
||||
"Usage: boundary managed-groups create oidc [options] [args]",
|
||||
"",
|
||||
" Create a oidc-type managed group. Example:",
|
||||
"",
|
||||
` $ boundary managed-groups create oidc -filter '"/token/email" == "doe@example.com"' -description "Oidc managed group for ProdOps"`,
|
||||
"",
|
||||
"",
|
||||
})
|
||||
|
||||
case "update":
|
||||
helpStr = base.WrapForHelpText([]string{
|
||||
"Usage: boundary managed-groups update oidc [options] [args]",
|
||||
"",
|
||||
" Update a oidc-type managed group given its ID. Example:",
|
||||
"",
|
||||
` $ boundary managed-groups update oidc -id acctoidc_1234567890 -name "devops" -description "Oidc managed group for DevOps"`,
|
||||
"",
|
||||
"",
|
||||
})
|
||||
}
|
||||
return helpStr + c.Flags().Help()
|
||||
}
|
||||
|
||||
func extraOidcFlagsFuncImpl(c *OidcCommand, _ *base.FlagSets, f *base.FlagSet) {
|
||||
for _, name := range flagsOidcMap[c.Func] {
|
||||
switch name {
|
||||
case "filter":
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: filterFlagName,
|
||||
Target: &c.flagFilter,
|
||||
Usage: "The filter defining the criteria against which an accounts's OIDC token and/or userinfo will be evaluated to determined membership at login time.",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func extraOidcFlagsHandlingFuncImpl(c *OidcCommand, _ *base.FlagSets, opts *[]managedgroups.Option) bool {
|
||||
switch c.flagFilter {
|
||||
case "null":
|
||||
c.UI.Error("Filter must be defined, and cannot be cleared.")
|
||||
return false
|
||||
|
||||
case "":
|
||||
if c.Func == "create" {
|
||||
c.UI.Error("The -filter flag must be provided when creating a managed group.")
|
||||
return false
|
||||
}
|
||||
|
||||
default:
|
||||
_, err := bexpr.CreateEvaluator(c.flagFilter)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Sprintf("Error when parsing filter to check validity: %v", err))
|
||||
return false
|
||||
}
|
||||
*opts = append(*opts, managedgroups.WithAttributes(map[string]interface{}{filterFlagName: c.flagFilter}))
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
// Code generated by "make api"; DO NOT EDIT.
|
||||
package managedgroupscmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/boundary/api"
|
||||
"github.com/hashicorp/boundary/api/managedgroups"
|
||||
"github.com/hashicorp/boundary/internal/cmd/base"
|
||||
"github.com/hashicorp/boundary/internal/cmd/common"
|
||||
"github.com/hashicorp/boundary/sdk/strutil"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
||||
func initOidcFlags() {
|
||||
flagsOnce.Do(func() {
|
||||
extraFlags := extraOidcActionsFlagsMapFunc()
|
||||
for k, v := range extraFlags {
|
||||
flagsOidcMap[k] = append(flagsOidcMap[k], v...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var (
|
||||
_ cli.Command = (*OidcCommand)(nil)
|
||||
_ cli.CommandAutocomplete = (*OidcCommand)(nil)
|
||||
)
|
||||
|
||||
type OidcCommand struct {
|
||||
*base.Command
|
||||
|
||||
Func string
|
||||
|
||||
plural string
|
||||
|
||||
extraOidcCmdVars
|
||||
}
|
||||
|
||||
func (c *OidcCommand) AutocompleteArgs() complete.Predictor {
|
||||
initOidcFlags()
|
||||
return complete.PredictAnything
|
||||
}
|
||||
|
||||
func (c *OidcCommand) AutocompleteFlags() complete.Flags {
|
||||
initOidcFlags()
|
||||
return c.Flags().Completions()
|
||||
}
|
||||
|
||||
func (c *OidcCommand) Synopsis() string {
|
||||
if extra := extraOidcSynopsisFunc(c); extra != "" {
|
||||
return extra
|
||||
}
|
||||
|
||||
synopsisStr := "managed group"
|
||||
|
||||
synopsisStr = fmt.Sprintf("%s %s", "oidc-type", synopsisStr)
|
||||
|
||||
return common.SynopsisFunc(c.Func, synopsisStr)
|
||||
}
|
||||
|
||||
func (c *OidcCommand) Help() string {
|
||||
initOidcFlags()
|
||||
|
||||
var helpStr string
|
||||
helpMap := common.HelpMap("managed group")
|
||||
|
||||
switch c.Func {
|
||||
default:
|
||||
|
||||
helpStr = c.extraOidcHelpFunc(helpMap)
|
||||
}
|
||||
|
||||
// Keep linter from complaining if we don't actually generate code using it
|
||||
_ = helpMap
|
||||
return helpStr
|
||||
}
|
||||
|
||||
var flagsOidcMap = map[string][]string{
|
||||
|
||||
"create": {"auth-method-id", "name", "description"},
|
||||
|
||||
"update": {"id", "name", "description", "version"},
|
||||
}
|
||||
|
||||
func (c *OidcCommand) Flags() *base.FlagSets {
|
||||
if len(flagsOidcMap[c.Func]) == 0 {
|
||||
return c.FlagSet(base.FlagSetNone)
|
||||
}
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "oidc-type managed group", flagsOidcMap, c.Func)
|
||||
|
||||
extraOidcFlagsFunc(c, set, f)
|
||||
|
||||
return set
|
||||
}
|
||||
|
||||
func (c *OidcCommand) Run(args []string) int {
|
||||
initOidcFlags()
|
||||
|
||||
switch c.Func {
|
||||
case "":
|
||||
return cli.RunResultHelp
|
||||
}
|
||||
|
||||
c.plural = "oidc-type managed group"
|
||||
switch c.Func {
|
||||
case "list":
|
||||
c.plural = "oidc-type managed groups"
|
||||
}
|
||||
|
||||
f := c.Flags()
|
||||
|
||||
if err := f.Parse(args); err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
if strutil.StrListContains(flagsOidcMap[c.Func], "id") && c.FlagId == "" {
|
||||
c.PrintCliError(errors.New("ID is required but not passed in via -id"))
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
var opts []managedgroups.Option
|
||||
|
||||
if strutil.StrListContains(flagsOidcMap[c.Func], "auth-method-id") {
|
||||
switch c.Func {
|
||||
case "create":
|
||||
if c.FlagAuthMethodId == "" {
|
||||
c.PrintCliError(errors.New("AuthMethod ID must be passed in via -auth-method-id or BOUNDARY_AUTH_METHOD_ID"))
|
||||
return base.CommandUserError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client, err := c.Client()
|
||||
if err != nil {
|
||||
c.PrintCliError(fmt.Errorf("Error creating API client: %s", err.Error()))
|
||||
return base.CommandCliError
|
||||
}
|
||||
managedgroupsClient := managedgroups.NewClient(client)
|
||||
|
||||
switch c.FlagName {
|
||||
case "":
|
||||
case "null":
|
||||
opts = append(opts, managedgroups.DefaultName())
|
||||
default:
|
||||
opts = append(opts, managedgroups.WithName(c.FlagName))
|
||||
}
|
||||
|
||||
switch c.FlagDescription {
|
||||
case "":
|
||||
case "null":
|
||||
opts = append(opts, managedgroups.DefaultDescription())
|
||||
default:
|
||||
opts = append(opts, managedgroups.WithDescription(c.FlagDescription))
|
||||
}
|
||||
|
||||
if c.FlagFilter != "" {
|
||||
opts = append(opts, managedgroups.WithFilter(c.FlagFilter))
|
||||
}
|
||||
|
||||
var version uint32
|
||||
|
||||
switch c.Func {
|
||||
case "update":
|
||||
switch c.FlagVersion {
|
||||
case 0:
|
||||
opts = append(opts, managedgroups.WithAutomaticVersioning(true))
|
||||
default:
|
||||
version = uint32(c.FlagVersion)
|
||||
}
|
||||
}
|
||||
|
||||
if ok := extraOidcFlagsHandlingFunc(c, f, &opts); !ok {
|
||||
return base.CommandUserError
|
||||
}
|
||||
|
||||
var result api.GenericResult
|
||||
|
||||
switch c.Func {
|
||||
|
||||
case "create":
|
||||
result, err = managedgroupsClient.Create(c.Context, c.FlagAuthMethodId, opts...)
|
||||
|
||||
case "update":
|
||||
result, err = managedgroupsClient.Update(c.Context, c.FlagId, version, opts...)
|
||||
|
||||
}
|
||||
|
||||
result, err = executeExtraOidcActions(c, result, err, managedgroupsClient, version, opts)
|
||||
|
||||
if err != nil {
|
||||
if apiErr := api.AsServerError(err); apiErr != nil {
|
||||
c.PrintApiError(apiErr, fmt.Sprintf("Error from controller when performing %s on %s", c.Func, c.plural))
|
||||
return base.CommandApiError
|
||||
}
|
||||
c.PrintCliError(fmt.Errorf("Error trying to %s %s: %s", c.Func, c.plural, err.Error()))
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
output, err := printCustomOidcActionOutput(c)
|
||||
if err != nil {
|
||||
c.PrintCliError(err)
|
||||
return base.CommandUserError
|
||||
}
|
||||
if output {
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
switch c.Func {
|
||||
}
|
||||
|
||||
switch base.Format(c.UI) {
|
||||
case "table":
|
||||
c.UI.Output(printItemTable(result))
|
||||
|
||||
case "json":
|
||||
if ok := c.PrintJsonItem(result); !ok {
|
||||
return base.CommandCliError
|
||||
}
|
||||
}
|
||||
|
||||
return base.CommandSuccess
|
||||
}
|
||||
|
||||
var (
|
||||
extraOidcActionsFlagsMapFunc = func() map[string][]string { return nil }
|
||||
extraOidcSynopsisFunc = func(*OidcCommand) string { return "" }
|
||||
extraOidcFlagsFunc = func(*OidcCommand, *base.FlagSets, *base.FlagSet) {}
|
||||
extraOidcFlagsHandlingFunc = func(*OidcCommand, *base.FlagSets, *[]managedgroups.Option) bool { return true }
|
||||
executeExtraOidcActions = func(_ *OidcCommand, inResult api.GenericResult, inErr error, _ *managedgroups.Client, _ uint32, _ []managedgroups.Option) (api.GenericResult, error) {
|
||||
return inResult, inErr
|
||||
}
|
||||
printCustomOidcActionOutput = func(*OidcCommand) (bool, error) { return false, nil }
|
||||
)
|
||||
@@ -113,7 +113,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "role", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "role", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "scope", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "scope", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "session", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "session", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "target", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "target", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ func (c *TcpCommand) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "tcp-type target", flagsTcpMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "tcp-type target", flagsTcpMap, c.Func)
|
||||
|
||||
extraTcpFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ func (c *Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "user", flagsMap[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "user", flagsMap, c.Func)
|
||||
|
||||
extraFlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"github.com/posener/complete"
|
||||
)
|
||||
|
||||
func PopulateCommonFlags(c *base.Command, f *base.FlagSet, resourceType string, flagNames []string) {
|
||||
for _, name := range flagNames {
|
||||
func PopulateCommonFlags(c *base.Command, f *base.FlagSet, resourceType string, flagNames map[string][]string, command string) {
|
||||
for _, name := range flagNames[command] {
|
||||
switch name {
|
||||
case "scope-id":
|
||||
f.StringVar(&base.StringVar{
|
||||
@@ -71,12 +71,18 @@ func PopulateCommonFlags(c *base.Command, f *base.FlagSet, resourceType string,
|
||||
Target: &c.FlagRecursive,
|
||||
Usage: "If set, the list operation will be applied recursively into child scopes, if supported by the type.",
|
||||
})
|
||||
case "filter":
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "filter",
|
||||
Target: &c.FlagFilter,
|
||||
Usage: "If set, the list operation will be filtered before being returned. The filter operates against each item in the list. Using single quotes is recommended as filters contain double quotes. See https://www.boundaryproject.io/docs/concepts/filtering/resource-listing for details.",
|
||||
})
|
||||
}
|
||||
}
|
||||
if command == "list" {
|
||||
for _, name := range flagNames[command] {
|
||||
switch name {
|
||||
case "filter":
|
||||
f.StringVar(&base.StringVar{
|
||||
Name: "filter",
|
||||
Target: &c.FlagFilter,
|
||||
Usage: "If set, the list operation will be filtered before being returned. The filter operates against each item in the list. Using single quotes is recommended as filters contain double quotes. See https://www.boundaryproject.io/docs/concepts/filtering/resource-listing for details.",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,6 +251,32 @@ var inputStructs = map[string][]*cmdInfo{
|
||||
VersionedActions: []string{"update"},
|
||||
},
|
||||
},
|
||||
"managedgroups": {
|
||||
{
|
||||
ResourceType: resource.ManagedGroup.String(),
|
||||
Pkg: "managedgroups",
|
||||
StdActions: []string{"read", "delete", "list"},
|
||||
IsAbstractType: true,
|
||||
Container: "AuthMethod",
|
||||
HasId: true,
|
||||
HasName: true,
|
||||
HasDescription: true,
|
||||
},
|
||||
{
|
||||
ResourceType: resource.ManagedGroup.String(),
|
||||
Pkg: "managedgroups",
|
||||
StdActions: []string{"create", "update"},
|
||||
SubActionPrefix: "oidc",
|
||||
HasExtraCommandVars: true,
|
||||
SkipNormalHelp: true,
|
||||
HasExtraHelpFunc: true,
|
||||
HasId: true,
|
||||
HasName: true,
|
||||
Container: "AuthMethod",
|
||||
HasDescription: true,
|
||||
VersionedActions: []string{"update"},
|
||||
},
|
||||
},
|
||||
"roles": {
|
||||
{
|
||||
ResourceType: resource.Role.String(),
|
||||
|
||||
@@ -195,7 +195,7 @@ func (c *{{ camelCase .SubActionPrefix }}Command) Flags() *base.FlagSets {
|
||||
|
||||
set := c.FlagSet(base.FlagSetHTTP | base.FlagSetClient | base.FlagSetOutputFormat)
|
||||
f := set.NewFlagSet("Command Options")
|
||||
common.PopulateCommonFlags(c.Command, f, "{{ if .SubActionPrefix }}{{ .SubActionPrefix }}-type {{ end }}{{ lowerSpaceCase .ResourceType }}", flags{{ camelCase .SubActionPrefix }}Map[c.Func])
|
||||
common.PopulateCommonFlags(c.Command, f, "{{ if .SubActionPrefix }}{{ .SubActionPrefix }}-type {{ end }}{{ lowerSpaceCase .ResourceType }}", flags{{ camelCase .SubActionPrefix }}Map, c.Func)
|
||||
|
||||
extra{{ camelCase .SubActionPrefix }}FlagsFunc(c, set, f)
|
||||
|
||||
|
||||
@@ -3200,6 +3200,14 @@
|
||||
"type": "object",
|
||||
"description": "The attributes that are applicable for the specific ManagedGroup type."
|
||||
},
|
||||
"member_ids": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Output only. The IDs of the current set of members (accounts) that are associated with this ManagedGroup.",
|
||||
"readOnly": true
|
||||
},
|
||||
"authorized_actions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -52,6 +52,8 @@ type ManagedGroup struct {
|
||||
AuthMethodId string `protobuf:"bytes,90,opt,name=auth_method_id,proto3" json:"auth_method_id,omitempty"`
|
||||
// The attributes that are applicable for the specific ManagedGroup type.
|
||||
Attributes *structpb.Struct `protobuf:"bytes,100,opt,name=attributes,proto3" json:"attributes,omitempty"`
|
||||
// Output only. The IDs of the current set of members (accounts) that are associated with this ManagedGroup.
|
||||
MemberIds []string `protobuf:"bytes,110,rep,name=member_ids,proto3" json:"member_ids,omitempty"`
|
||||
// Output only. The available actions on this resource for this user.
|
||||
AuthorizedActions []string `protobuf:"bytes,300,rep,name=authorized_actions,proto3" json:"authorized_actions,omitempty"`
|
||||
}
|
||||
@@ -158,6 +160,13 @@ func (x *ManagedGroup) GetAttributes() *structpb.Struct {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ManagedGroup) GetMemberIds() []string {
|
||||
if x != nil {
|
||||
return x.MemberIds
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ManagedGroup) GetAuthorizedActions() []string {
|
||||
if x != nil {
|
||||
return x.AuthorizedActions
|
||||
@@ -235,7 +244,7 @@ var file_controller_api_resources_managedgroups_v1_managed_group_proto_rawDesc =
|
||||
0x6f, 0x70, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2a, 0x63, 0x6f, 0x6e, 0x74, 0x72,
|
||||
0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6f, 0x70, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd5, 0x04, 0x0a, 0x0c, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf5, 0x04, 0x0a, 0x0c, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||
0x64, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18,
|
||||
0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c,
|
||||
@@ -269,7 +278,9 @@ var file_controller_api_resources_managedgroups_v1_managed_group_proto_rawDesc =
|
||||
0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x64, 0x20, 0x01, 0x28,
|
||||
0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x04, 0xa0, 0xda, 0x29, 0x01,
|
||||
0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x12,
|
||||
0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a,
|
||||
0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x6e, 0x20, 0x03, 0x28, 0x09,
|
||||
0x52, 0x0a, 0x6d, 0x65, 0x6d, 0x62, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x12, 0x2f, 0x0a, 0x12,
|
||||
0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x18, 0xac, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x61, 0x75, 0x74, 0x68, 0x6f,
|
||||
0x72, 0x69, 0x7a, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x59, 0x0a,
|
||||
|
||||
@@ -43,6 +43,9 @@ message ManagedGroup {
|
||||
// The attributes that are applicable for the specific ManagedGroup type.
|
||||
google.protobuf.Struct attributes = 100 [(custom_options.v1.generate_sdk_option) = true];
|
||||
|
||||
// Output only. The IDs of the current set of members (accounts) that are associated with this ManagedGroup.
|
||||
repeated string member_ids = 110 [json_name="member_ids"];
|
||||
|
||||
// Output only. The available actions on this resource for this user.
|
||||
repeated string authorized_actions = 300 [json_name="authorized_actions"];
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ func (s Service) GetManagedGroup(ctx context.Context, req *pbs.GetManagedGroupRe
|
||||
if authResults.Error != nil {
|
||||
return nil, authResults.Error
|
||||
}
|
||||
mg, err := s.getFromRepo(ctx, req.GetId())
|
||||
mg, memberIds, err := s.getFromRepo(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -163,6 +163,9 @@ func (s Service) GetManagedGroup(ctx context.Context, req *pbs.GetManagedGroupRe
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, mg.GetPublicId(), IdActions[auth.SubtypeFromId(mg.GetPublicId())]).Strings()))
|
||||
}
|
||||
if outputFields.Has(globals.MemberIdsField) {
|
||||
outputOpts = append(outputOpts, handlers.WithMemberIds(memberIds))
|
||||
}
|
||||
|
||||
item, err := toProto(ctx, mg, outputOpts...)
|
||||
if err != nil {
|
||||
@@ -266,26 +269,37 @@ func (s Service) DeleteManagedGroup(ctx context.Context, req *pbs.DeleteManagedG
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s Service) getFromRepo(ctx context.Context, id string) (auth.ManagedGroup, error) {
|
||||
func (s Service) getFromRepo(ctx context.Context, id string) (auth.ManagedGroup, []string, error) {
|
||||
var out auth.ManagedGroup
|
||||
var memberIds []string
|
||||
switch auth.SubtypeFromId(id) {
|
||||
case auth.OidcSubtype:
|
||||
repo, err := s.oidcRepoFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
mg, err := repo.LookupManagedGroup(ctx, id)
|
||||
if err != nil {
|
||||
if errors.IsNotFoundError(err) {
|
||||
return nil, handlers.NotFoundErrorf("ManagedGroup %q doesn't exist.", id)
|
||||
return nil, nil, handlers.NotFoundErrorf("ManagedGroup %q doesn't exist.", id)
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
ids, err := repo.ListManagedGroupMembershipsByGroup(ctx, mg.GetPublicId())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if len(ids) > 0 {
|
||||
memberIds = make([]string, len(ids))
|
||||
for i, v := range ids {
|
||||
memberIds[i] = v.MemberId
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
out = mg
|
||||
default:
|
||||
return nil, handlers.NotFoundErrorf("Unrecognized id.")
|
||||
return nil, nil, handlers.NotFoundErrorf("Unrecognized id.")
|
||||
}
|
||||
return out, nil
|
||||
return out, memberIds, nil
|
||||
}
|
||||
|
||||
func (s Service) createOidcInRepo(ctx context.Context, am auth.AuthMethod, item *pb.ManagedGroup) (*oidc.ManagedGroup, error) {
|
||||
@@ -529,6 +543,9 @@ func toProto(ctx context.Context, in auth.ManagedGroup, opt ...handlers.Option)
|
||||
if outputFields.Has(globals.AuthorizedActionsField) {
|
||||
out.AuthorizedActions = opts.WithAuthorizedActions
|
||||
}
|
||||
if outputFields.Has(globals.MemberIdsField) {
|
||||
out.MemberIds = opts.WithMemberIds
|
||||
}
|
||||
switch i := in.(type) {
|
||||
case *oidc.ManagedGroup:
|
||||
if outputFields.Has(globals.TypeField) {
|
||||
|
||||
@@ -106,18 +106,33 @@ func TestGet(t *testing.T) {
|
||||
oidc.WithSigningAlgs(oidc.RS256),
|
||||
oidc.WithApiUrl(oidc.TestConvertToUrls(t, "https://www.alice.com/callback")[0]),
|
||||
)
|
||||
oidcA := oidc.TestAccount(t, conn, oidcAm, "test-subject")
|
||||
omg := oidc.TestManagedGroup(t, conn, oidcAm, testFakeManagedGroupFilter)
|
||||
|
||||
// Set up managed group before getting. First get the current
|
||||
// managed group to make sure we have the right version, then ensure
|
||||
// the account is a member so we can test that return value.
|
||||
oidcRepo, err := oidcRepoFn()
|
||||
require.NoError(t, err)
|
||||
currMg, err := oidcRepo.LookupManagedGroup(ctx, omg.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
_, _, err = oidcRepo.SetManagedGroupMemberships(ctx, oidcAm, oidcA, []*oidc.ManagedGroup{currMg})
|
||||
require.NoError(t, err)
|
||||
// Fetch the group once more to get the updated time
|
||||
currMg, err = oidcRepo.LookupManagedGroup(ctx, omg.GetPublicId())
|
||||
require.NoError(t, err)
|
||||
|
||||
oidcWireManagedGroup := pb.ManagedGroup{
|
||||
Id: omg.GetPublicId(),
|
||||
AuthMethodId: omg.GetAuthMethodId(),
|
||||
CreatedTime: omg.GetCreateTime().GetTimestamp(),
|
||||
UpdatedTime: omg.GetUpdateTime().GetTimestamp(),
|
||||
UpdatedTime: currMg.GetUpdateTime().GetTimestamp(),
|
||||
Scope: &scopepb.ScopeInfo{Id: org.GetPublicId(), Type: scope.Org.String(), ParentScopeId: scope.Global.String()},
|
||||
Version: 1,
|
||||
Version: currMg.Version,
|
||||
Type: "oidc",
|
||||
Attributes: &structpb.Struct{Fields: map[string]*structpb.Value{"filter": structpb.NewStringValue(omg.GetFilter())}},
|
||||
AuthorizedActions: oidcAuthorizedActions,
|
||||
MemberIds: []string{oidcA.GetPublicId()},
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
|
||||
@@ -72,4 +72,16 @@ func Test_GetOpts(t *testing.T) {
|
||||
opts = GetOpts(WithManagedGroupIds(out))
|
||||
require.Equal(out, opts.WithManagedGroupIds)
|
||||
})
|
||||
t.Run("WithMemberIds", func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
opts := GetOpts()
|
||||
assert.Nil(opts.WithMemberIds)
|
||||
|
||||
out := []string{"foobar"}
|
||||
|
||||
opts = GetOpts(WithMemberIds(out))
|
||||
require.Equal(out, opts.WithMemberIds)
|
||||
})
|
||||
}
|
||||
@@ -31,6 +31,7 @@ type options struct {
|
||||
WithAuthorizedActions []string
|
||||
WithAuthorizedCollectionActions map[string]*structpb.ListValue
|
||||
WithManagedGroupIds []string
|
||||
WithMemberIds []string
|
||||
}
|
||||
|
||||
func getDefaultOptions() options {
|
||||
@@ -100,3 +101,11 @@ func WithManagedGroupIds(ids []string) Option {
|
||||
o.WithManagedGroupIds = ids
|
||||
}
|
||||
}
|
||||
|
||||
// WithMemberIds provides an option when creating responses to include the given
|
||||
// member IDs if allowed
|
||||
func WithMemberIds(ids []string) Option {
|
||||
return func(o *options) {
|
||||
o.WithMemberIds = ids
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user