diff --git a/Makefile b/Makefile index b996c1b0c..140b34ca8 100644 --- a/Makefile +++ b/Makefile @@ -238,9 +238,11 @@ protobuild: @protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/users/user.pb.go @protoc-go-inject-tag -input=./internal/gen/controller/api/services/user_service.pb.go @protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/workers/worker.pb.go + @protoc-go-inject-tag -input=./internal/gen/controller/api/services/worker_service.pb.go @protoc-go-inject-tag -input=./internal/gen/controller/api/services/session_recording_service.pb.go @protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/session_recordings/session_recording.pb.go - @protoc-go-inject-tag -input=./internal/gen/controller/api/services/worker_service.pb.go + @protoc-go-inject-tag -input=./internal/gen/controller/api/services/alias_service.pb.go + @protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/aliases/alias.pb.go @protoc-go-inject-tag -input=./internal/gen/controller/servers/services/server_coordination_service.pb.go @protoc-go-inject-tag -input=./internal/gen/controller/servers/servers.pb.go @protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/policies/policy.pb.go diff --git a/api/aliases/alias.gen.go b/api/aliases/alias.gen.go new file mode 100644 index 000000000..8904ac12f --- /dev/null +++ b/api/aliases/alias.gen.go @@ -0,0 +1,447 @@ +// Code generated by "make api"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package aliases + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/url" + "slices" + "time" + + "github.com/hashicorp/boundary/api" + "github.com/hashicorp/boundary/api/scopes" +) + +type Alias struct { + Id string `json:"id,omitempty"` + ScopeId string `json:"scope_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"` + Value string `json:"value,omitempty"` + DestinationId string `json:"destination_id,omitempty"` + Attributes map[string]interface{} `json:"attributes,omitempty"` + AuthorizedActions []string `json:"authorized_actions,omitempty"` + + response *api.Response +} + +type AliasReadResult struct { + Item *Alias + response *api.Response +} + +func (n AliasReadResult) GetItem() *Alias { + return n.Item +} + +func (n AliasReadResult) GetResponse() *api.Response { + return n.response +} + +type AliasCreateResult = AliasReadResult +type AliasUpdateResult = AliasReadResult + +type AliasDeleteResult struct { + response *api.Response +} + +// GetItem will always be nil for AliasDeleteResult +func (n AliasDeleteResult) GetItem() interface{} { + return nil +} + +func (n AliasDeleteResult) GetResponse() *api.Response { + return n.response +} + +type AliasListResult struct { + Items []*Alias `json:"items,omitempty"` + EstItemCount uint `json:"est_item_count,omitempty"` + RemovedIds []string `json:"removed_ids,omitempty"` + ListToken string `json:"list_token,omitempty"` + ResponseType string `json:"response_type,omitempty"` + response *api.Response +} + +func (n AliasListResult) GetItems() []*Alias { + return n.Items +} + +func (n AliasListResult) GetEstItemCount() uint { + return n.EstItemCount +} + +func (n AliasListResult) GetRemovedIds() []string { + return n.RemovedIds +} + +func (n AliasListResult) GetListToken() string { + return n.ListToken +} + +func (n AliasListResult) GetResponseType() string { + return n.ResponseType +} + +func (n AliasListResult) 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, scopeId string, opt ...Option) (*AliasCreateResult, error) { + if scopeId == "" { + return nil, fmt.Errorf("empty scopeId value passed into Create request") + } + + opts, apiOpts := getOpts(opt...) + + if c.client == nil { + return nil, fmt.Errorf("nil client") + } + + opts.postMap["scope_id"] = scopeId + + req, err := c.client.NewRequest(ctx, "POST", "aliases", 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(AliasCreateResult) + target.Item = new(Alias) + 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, id string, opt ...Option) (*AliasReadResult, error) { + if id == "" { + return nil, fmt.Errorf("empty id 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("aliases/%s", url.PathEscape(id)), 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(AliasReadResult) + target.Item = new(Alias) + 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, id string, version uint32, opt ...Option) (*AliasUpdateResult, error) { + if id == "" { + return nil, fmt.Errorf("empty id 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, id, 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("aliases/%s", url.PathEscape(id)), 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(AliasUpdateResult) + target.Item = new(Alias) + 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, id string, opt ...Option) (*AliasDeleteResult, error) { + if id == "" { + return nil, fmt.Errorf("empty id 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("aliases/%s", url.PathEscape(id)), 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 := &AliasDeleteResult{ + response: resp, + } + return target, nil +} + +func (c *Client) List(ctx context.Context, scopeId string, opt ...Option) (*AliasListResult, error) { + if scopeId == "" { + return nil, fmt.Errorf("empty scopeId value passed into List request") + } + if c.client == nil { + return nil, fmt.Errorf("nil client") + } + + opts, apiOpts := getOpts(opt...) + opts.queryMap["scope_id"] = scopeId + + req, err := c.client.NewRequest(ctx, "GET", "aliases", 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(AliasListResult) + 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 + if target.ResponseType == "complete" || target.ResponseType == "" { + return target, nil + } + // If there are more results, automatically fetch the rest of the results. + // idToIndex keeps a map from the ID of an item to its index in target.Items. + // This is used to update updated items in-place and remove deleted items + // from the result after pagination is done. + idToIndex := map[string]int{} + for i, item := range target.Items { + idToIndex[item.Id] = i + } + // Removed IDs in the response may contain duplicates, + // maintain a set to avoid returning duplicates to the user. + removedIds := map[string]struct{}{} + for { + req, err := c.client.NewRequest(ctx, "GET", "aliases", nil, apiOpts...) + if err != nil { + return nil, fmt.Errorf("error creating List request: %w", err) + } + + opts.queryMap["list_token"] = target.ListToken + 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) + } + + page := new(AliasListResult) + apiErr, err := resp.Decode(page) + if err != nil { + return nil, fmt.Errorf("error decoding List response: %w", err) + } + if apiErr != nil { + return nil, apiErr + } + for _, item := range page.Items { + if i, ok := idToIndex[item.Id]; ok { + // Item has already been seen at index i, update in-place + target.Items[i] = item + } else { + target.Items = append(target.Items, item) + idToIndex[item.Id] = len(target.Items) - 1 + } + } + for _, removedId := range page.RemovedIds { + removedIds[removedId] = struct{}{} + } + target.EstItemCount = page.EstItemCount + target.ListToken = page.ListToken + target.ResponseType = page.ResponseType + target.response = resp + if target.ResponseType == "complete" { + break + } + } + for _, removedId := range target.RemovedIds { + if i, ok := idToIndex[removedId]; ok { + // Remove the item at index i without preserving order + // https://github.com/golang/go/wiki/SliceTricks#delete-without-preserving-order + target.Items[i] = target.Items[len(target.Items)-1] + target.Items = target.Items[:len(target.Items)-1] + // Update the index of the last element + idToIndex[target.Items[i].Id] = i + } + } + for deletedId := range removedIds { + target.RemovedIds = append(target.RemovedIds, deletedId) + } + // Sort to make response deterministic + slices.Sort(target.RemovedIds) + // Since we paginated to the end, we can avoid confusion + // for the user by setting the estimated item count to the + // length of the items slice. If we don't set this here, it + // will equal the value returned in the last response, which is + // often much smaller than the total number returned. + target.EstItemCount = uint(len(target.Items)) + // Sort the results again since in-place updates and deletes + // may have shuffled items. We sort by created time descending + // (most recently created first), same as the API. + slices.SortFunc(target.Items, func(i, j *Alias) int { + return j.CreatedTime.Compare(i.CreatedTime) + }) + // Finally, since we made at least 2 requests to the server to fulfill this + // function call, resp.Body and resp.Map will only contain the most recent response. + // Overwrite them with the true response. + target.response.Body.Reset() + if err := json.NewEncoder(target.response.Body).Encode(target); err != nil { + return nil, fmt.Errorf("error encoding final JSON list response: %w", err) + } + if err := json.Unmarshal(target.response.Body.Bytes(), &target.response.Map); err != nil { + return nil, fmt.Errorf("error encoding final map list response: %w", err) + } + // Note: the HTTP response body is consumed by resp.Decode in the loop, + // so it doesn't need to be updated (it will always be, and has always been, empty). + return target, nil +} diff --git a/api/aliases/option.gen.go b/api/aliases/option.gen.go new file mode 100644 index 000000000..102710a89 --- /dev/null +++ b/api/aliases/option.gen.go @@ -0,0 +1,158 @@ +// Code generated by "make api"; DO NOT EDIT. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package aliases + +import ( + "strconv" + "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 the 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 + withListToken string + withRecursive bool +} + +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 + } + if opts.withListToken != "" { + opts.queryMap["list_token"] = opts.withListToken + } + if opts.withRecursive { + opts.queryMap["recursive"] = strconv.FormatBool(opts.withRecursive) + } + 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 + } +} + +// WithListToken tells the API to use the provided list token +// for listing operations on this resource. +func WithListToken(listToken string) Option { + return func(o *options) { + o.withListToken = listToken + } +} + +// 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) + } +} + +// WithRecursive tells the API to use recursion for listing operations on this +// resource +func WithRecursive(recurse bool) Option { + return func(o *options) { + o.withRecursive = true + } +} + +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 WithDestinationId(inDestinationId string) Option { + return func(o *options) { + o.postMap["destination_id"] = inDestinationId + } +} + +func DefaultDestinationId() Option { + return func(o *options) { + o.postMap["destination_id"] = nil + } +} + +func WithName(inName string) Option { + return func(o *options) { + o.postMap["name"] = inName + } +} + +func DefaultName() Option { + return func(o *options) { + o.postMap["name"] = nil + } +} + +func WithValue(inValue string) Option { + return func(o *options) { + o.postMap["value"] = inValue + } +} diff --git a/globals/fields.go b/globals/fields.go index cac3a68e2..1184aacb5 100644 --- a/globals/fields.go +++ b/globals/fields.go @@ -119,4 +119,6 @@ const ( StoragePolicyIdField = "storage_policy_id" RetainUntilField = "retain_until" DeleteAfterField = "delete_after" + DestinationIdField = "destination_id" + ValueField = "value" ) diff --git a/internal/alias/target/store/alias.pb.go b/internal/alias/target/store/alias.pb.go index 8d1a0cc25..a80a513d8 100644 --- a/internal/alias/target/store/alias.pb.go +++ b/internal/alias/target/store/alias.pb.go @@ -11,6 +11,7 @@ package store import ( timestamp "github.com/hashicorp/boundary/internal/db/timestamp" + _ "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -179,38 +180,52 @@ var file_controller_storage_alias_target_store_v1_alias_proto_rawDesc = []byte{ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x28, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x2e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x76, 0x31, - 0x1a, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f, - 0x72, 0x61, 0x67, 0x65, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x76, - 0x31, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0xff, 0x02, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, - 0x65, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, - 0x65, 0x49, 0x64, 0x12, 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, - 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x4b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, - 0x65, 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x64, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x68, 0x6f, - 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x68, 0x6f, 0x73, - 0x74, 0x49, 0x64, 0x42, 0x41, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, - 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x61, 0x6c, - 0x69, 0x61, 0x73, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, - 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 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, 0x1a, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, + 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xa8, 0x04, + 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, + 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, + 0x69, 0x63, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, 0x12, + 0x4b, 0x0a, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x4b, 0x0a, 0x0b, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x73, + 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x10, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, 0x04, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x40, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x1e, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x12, 0xc2, 0xdd, 0x29, 0x0e, + 0x0a, 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4a, 0x0a, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x23, 0xc2, + 0xdd, 0x29, 0x1f, 0x0a, 0x0d, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x49, 0x64, 0x12, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x52, 0x0d, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, + 0x64, 0x12, 0x55, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x3c, 0xc2, 0xdd, 0x29, 0x38, 0x0a, 0x06, 0x48, 0x6f, 0x73, 0x74, 0x49, 0x64, + 0x12, 0x2e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x61, + 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, + 0x52, 0x06, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x42, 0x41, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x2f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2f, + 0x73, 0x74, 0x6f, 0x72, 0x65, 0x3b, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/internal/api/genapi/input.go b/internal/api/genapi/input.go index 3aa2d7dea..6e5af8b53 100644 --- a/internal/api/genapi/input.go +++ b/internal/api/genapi/input.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/boundary/internal/gen/controller/api" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/accounts" + "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/aliases" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authmethods" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/authtokens" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/billing" @@ -762,6 +763,30 @@ var inputStructs = []*structInfo{ createResponseTypes: []string{CreateResponseType, ReadResponseType, UpdateResponseType, DeleteResponseType, ListResponseType}, }, + // Alias related resources + { + inProto: &aliases.Alias{}, + outFile: "aliases/alias.gen.go", + templates: []*template.Template{ + clientTemplate, + commonCreateTemplate, + readTemplate, + updateTemplate, + deleteTemplate, + listTemplate, + }, + fieldOverrides: []fieldInfo{ + { + Name: "Value", + SkipDefault: true, + }, + }, + pluralResourceName: "aliases", + versionEnabled: true, + createResponseTypes: []string{CreateResponseType, ReadResponseType, UpdateResponseType, DeleteResponseType, ListResponseType}, + recursiveListing: true, + }, + // Storage related resources { inProto: &storagebuckets.StorageBucket{}, diff --git a/internal/daemon/controller/common/common.go b/internal/daemon/controller/common/common.go index d73342764..8b8dd41dc 100644 --- a/internal/daemon/controller/common/common.go +++ b/internal/daemon/controller/common/common.go @@ -4,6 +4,7 @@ package common import ( + "github.com/hashicorp/boundary/internal/alias/target" "github.com/hashicorp/boundary/internal/auth" "github.com/hashicorp/boundary/internal/auth/ldap" "github.com/hashicorp/boundary/internal/auth/oidc" @@ -41,6 +42,7 @@ type ( WorkerAuthRepoStorageFactory func() (*server.WorkerAuthRepositoryStorage, error) PluginStorageBucketRepoFactory func() (*pluginstorage.Repository, error) BillingRepoFactory func() (*billing.Repository, error) + TargetAliasRepoFactory func() (*target.Repository, error) ) // Downstreamers provides at least a minimum interface that must be met by a diff --git a/internal/daemon/controller/controller.go b/internal/daemon/controller/controller.go index 5e0f90b58..4136fb399 100644 --- a/internal/daemon/controller/controller.go +++ b/internal/daemon/controller/controller.go @@ -11,6 +11,7 @@ import ( "sync" "sync/atomic" + target2 "github.com/hashicorp/boundary/internal/alias/target" "github.com/hashicorp/boundary/internal/auth" "github.com/hashicorp/boundary/internal/auth/ldap" "github.com/hashicorp/boundary/internal/auth/oidc" @@ -150,6 +151,7 @@ type Controller struct { TargetRepoFn target.RepositoryFactory WorkerAuthRepoStorageFn common.WorkerAuthRepoStorageFactory BillingRepoFn common.BillingRepoFactory + TargetAliasRepoFn common.TargetAliasRepoFactory scheduler *scheduler.Scheduler @@ -453,6 +455,9 @@ func New(ctx context.Context, conf *Config) (*Controller, error) { c.BillingRepoFn = func() (*billing.Repository, error) { return billing.NewRepository(ctx, dbase) } + c.TargetAliasRepoFn = func() (*target2.Repository, error) { + return target2.NewRepository(ctx, dbase, dbase, c.kms) + } // Check that credentials are available at startup, to avoid some harmless // but nasty-looking errors diff --git a/internal/daemon/controller/handler.go b/internal/daemon/controller/handler.go index 88348c6c3..c3dfb38b7 100644 --- a/internal/daemon/controller/handler.go +++ b/internal/daemon/controller/handler.go @@ -22,6 +22,7 @@ import ( "github.com/hashicorp/boundary/internal/daemon/common" "github.com/hashicorp/boundary/internal/daemon/controller/auth" "github.com/hashicorp/boundary/internal/daemon/controller/handlers/accounts" + "github.com/hashicorp/boundary/internal/daemon/controller/handlers/aliases" "github.com/hashicorp/boundary/internal/daemon/controller/handlers/authmethods" "github.com/hashicorp/boundary/internal/daemon/controller/handlers/authtokens" "github.com/hashicorp/boundary/internal/daemon/controller/handlers/billing" @@ -333,6 +334,18 @@ func (c *Controller) registerGrpcServices(s *grpc.Server) error { } services.RegisterWorkerServiceServer(s, ws) } + if _, ok := currentServices[services.AliasService_ServiceDesc.ServiceName]; !ok { + as, err := aliases.NewService( + c.baseContext, + c.TargetAliasRepoFn, + c.IamRepoFn, + c.conf.RawConfig.Controller.MaxPageSize, + ) + if err != nil { + return fmt.Errorf("failed to create alias handler service: %w", err) + } + services.RegisterAliasServiceServer(s, as) + } if _, ok := currentServices[services.CredentialService_ServiceDesc.ServiceName]; !ok { c, err := credentials.NewService( c.baseContext, @@ -419,10 +432,10 @@ func registerGrpcGatewayEndpoints(ctx context.Context, gwMux *runtime.ServeMux, return fmt.Errorf("failed to register session recording service handler: %w", err) } if err := services.RegisterStorageBucketServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil { - return fmt.Errorf("failed to register storage bucket handler: %w", err) + return fmt.Errorf("failed to register storage bucket service handler: %w", err) } - if err := services.RegisterSessionRecordingServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil { - return fmt.Errorf("failed to register session recording handler: %w", err) + if err := services.RegisterAliasServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil { + return fmt.Errorf("failed to register alias service handler: %w", err) } if err := services.RegisterPolicyServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil { return fmt.Errorf("failed to register policy handler: %w", err) diff --git a/internal/daemon/controller/handler_test.go b/internal/daemon/controller/handler_test.go index 4b386ff7f..90c19bd5f 100644 --- a/internal/daemon/controller/handler_test.go +++ b/internal/daemon/controller/handler_test.go @@ -109,6 +109,8 @@ func TestHandleImplementedPaths(t *testing.T) { "GET": { "v1/accounts", "v1/accounts/someid", + "v1/aliases", + "v1/aliases/someid", "v1/auth-methods", "v1/auth-methods/someid", "v1/auth-methods/someid:authenticate:callback", @@ -142,6 +144,7 @@ func TestHandleImplementedPaths(t *testing.T) { "POST": { // Creation end points "v1/accounts", + "v1/aliases", "v1/auth-methods", "v1/credential-stores", "v1/groups", @@ -184,6 +187,7 @@ func TestHandleImplementedPaths(t *testing.T) { }, "DELETE": { "v1/accounts/someid", + "v1/aliases/someid", "v1/auth-methods/someid", "v1/auth-tokens/someid", "v1/credential-stores/someid", @@ -199,6 +203,7 @@ func TestHandleImplementedPaths(t *testing.T) { }, "PATCH": { "v1/accounts/someid", + "v1/aliases/someid", "v1/auth-methods/someid", "v1/credential-stores/someid", "v1/groups/someid", diff --git a/internal/daemon/controller/handlers/aliases/alias_service.go b/internal/daemon/controller/handlers/aliases/alias_service.go index 4cf44b9d9..6d0c99380 100644 --- a/internal/daemon/controller/handlers/aliases/alias_service.go +++ b/internal/daemon/controller/handlers/aliases/alias_service.go @@ -4,11 +4,34 @@ package aliases import ( + "context" + "fmt" + + "github.com/hashicorp/boundary/globals" + "github.com/hashicorp/boundary/internal/alias/target" + "github.com/hashicorp/boundary/internal/alias/target/store" + "github.com/hashicorp/boundary/internal/daemon/controller/auth" + "github.com/hashicorp/boundary/internal/daemon/controller/common" + "github.com/hashicorp/boundary/internal/daemon/controller/common/scopeids" + "github.com/hashicorp/boundary/internal/daemon/controller/handlers" + "github.com/hashicorp/boundary/internal/errors" + pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services" + "github.com/hashicorp/boundary/internal/listtoken" + "github.com/hashicorp/boundary/internal/pagination" + "github.com/hashicorp/boundary/internal/perms" + "github.com/hashicorp/boundary/internal/requests" "github.com/hashicorp/boundary/internal/types/action" "github.com/hashicorp/boundary/internal/types/resource" + "github.com/hashicorp/boundary/internal/types/scope" + pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/aliases" + "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" + "google.golang.org/grpc/codes" + "google.golang.org/protobuf/types/known/wrapperspb" ) var ( + maskManager handlers.MaskManager + // IdActions contains the set of actions that can be performed on // individual resources IdActions = action.NewActionSet( @@ -27,6 +50,588 @@ var ( ) func init() { - // TODO: refactor to remove idActionsMap and CollectionActions package variables + var err error + if maskManager, err = handlers.NewMaskManager( + context.Background(), + handlers.MaskDestination{&store.Alias{}}, + handlers.MaskSource{&pb.Alias{}, &pb.AuthorizeSessionArguments{}}, + ); err != nil { + panic(err) + } + + // TODO: refactor to remove IdActionsMap and CollectionActions package variables action.RegisterResource(resource.Alias, action.Union(IdActions), CollectionActions) } + +// Service handles requests as described by the pbs.AliasServiceServer interface. +type Service struct { + pbs.UnsafeAliasServiceServer + + repoFn common.TargetAliasRepoFactory + iamRepoFn common.IamRepoFactory + maxPageSize uint +} + +var _ pbs.AliasServiceServer = (*Service)(nil) + +// NewService returns a alias service which handles alias related requests to boundary. +func NewService(ctx context.Context, repo common.TargetAliasRepoFactory, iamRepo common.IamRepoFactory, maxPageSize uint) (Service, error) { + const op = "aliasess.NewService" + if iamRepo == nil { + return Service{}, errors.New(ctx, errors.InvalidParameter, op, "missing iam repository") + } + if repo == nil { + return Service{}, errors.New(ctx, errors.InvalidParameter, op, "missing alias repository") + } + if maxPageSize == 0 { + maxPageSize = uint(globals.DefaultMaxPageSize) + } + return Service{repoFn: repo, iamRepoFn: iamRepo, maxPageSize: maxPageSize}, nil +} + +// ListAliases implements the interface pbs.AliasServiceServer. +func (s Service) ListAliases(ctx context.Context, req *pbs.ListAliasesRequest) (*pbs.ListAliasesResponse, error) { + const op = "aliases.(Service).ListAliases" + if err := validateListRequest(ctx, req); err != nil { + return nil, err + } + authResults := s.authResult(ctx, req.GetScopeId(), action.List) + if authResults.Error != nil { + // If it's forbidden, and it's a recursive request, and they're + // successfully authenticated but just not authorized, keep going as we + // may have authorization on downstream scopes. Or, if they've not + // authenticated, still process in case u_anon has permissions. + if (authResults.Error == handlers.ForbiddenError() || authResults.Error == handlers.UnauthenticatedError()) && + req.GetRecursive() && + authResults.AuthenticationFinished { + } else { + return nil, authResults.Error + } + } + + scopeIds, scopeInfoMap, err := scopeids.GetListingScopeIds( + ctx, s.iamRepoFn, authResults, req.GetScopeId(), resource.Alias, req.GetRecursive()) + if err != nil { + return nil, err + } + // If no scopes match, return an empty response + if len(scopeIds) == 0 { + return &pbs.ListAliasesResponse{}, nil + } + + pageSize := int(s.maxPageSize) + // Use the requested page size only if it is smaller than + // the configured max. + if req.GetPageSize() != 0 && uint(req.GetPageSize()) < s.maxPageSize { + pageSize = int(req.GetPageSize()) + } + + var filterItemFn func(ctx context.Context, item *target.Alias) (bool, error) + switch { + case req.GetFilter() != "": + // Only use a filter if we need to + filter, err := handlers.NewFilter(ctx, req.GetFilter()) + if err != nil { + return nil, err + } + filterItemFn = func(ctx context.Context, item *target.Alias) (bool, error) { + outputOpts, ok := newOutputOpts(ctx, item, scopeInfoMap, authResults) + if !ok { + return false, nil + } + pbItem, err := toProto(ctx, item, outputOpts...) + if err != nil { + return false, err + } + return filter.Match(pbItem), nil + } + default: + filterItemFn = func(ctx context.Context, item *target.Alias) (bool, error) { + return true, nil + } + } + + grantsHash, err := authResults.GrantsHash(ctx) + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + + repo, err := s.repoFn() + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + var listResp *pagination.ListResponse[*target.Alias] + var sortBy string + if req.GetListToken() == "" { + sortBy = "created_time" + listResp, err = target.ListAliases(ctx, grantsHash, pageSize, filterItemFn, repo, scopeIds) + if err != nil { + return nil, err + } + } else { + listToken, err := handlers.ParseListToken(ctx, req.GetListToken(), resource.Alias, grantsHash) + if err != nil { + return nil, err + } + switch st := listToken.Subtype.(type) { + case *listtoken.PaginationToken: + sortBy = "created_time" + listResp, err = target.ListAliasesPage(ctx, grantsHash, pageSize, filterItemFn, listToken, repo, scopeIds) + if err != nil { + return nil, err + } + case *listtoken.StartRefreshToken: + sortBy = "updated_time" + listResp, err = target.ListAliasesRefresh(ctx, grantsHash, pageSize, filterItemFn, listToken, repo, scopeIds) + if err != nil { + return nil, err + } + case *listtoken.RefreshToken: + sortBy = "updated_time" + listResp, err = target.ListAliasesRefreshPage(ctx, grantsHash, pageSize, filterItemFn, listToken, repo, scopeIds) + if err != nil { + return nil, err + } + default: + return nil, handlers.ApiErrorWithCodeAndMessage(codes.InvalidArgument, "unexpected list token subtype: %T", st) + } + } + + finalItems := make([]*pb.Alias, 0, len(listResp.Items)) + for _, item := range listResp.Items { + outputOpts, ok := newOutputOpts(ctx, item, scopeInfoMap, authResults) + if !ok { + continue + } + item, err := toProto(ctx, item, outputOpts...) + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + finalItems = append(finalItems, item) + } + respType := "delta" + if listResp.CompleteListing { + respType = "complete" + } + resp := &pbs.ListAliasesResponse{ + Items: finalItems, + EstItemCount: uint32(listResp.EstimatedItemCount), + RemovedIds: listResp.DeletedIds, + ResponseType: respType, + SortBy: sortBy, + SortDir: "desc", + } + if listResp.ListToken != nil { + resp.ListToken, err = handlers.MarshalListToken(ctx, listResp.ListToken, pbs.ResourceType_RESOURCE_TYPE_ALIAS) + if err != nil { + return nil, err + } + } + return resp, nil +} + +// GetAliass implements the interface pbs.AliasServiceServer. +func (s Service) GetAlias(ctx context.Context, req *pbs.GetAliasRequest) (*pbs.GetAliasResponse, error) { + const op = "aliases.(Service).GetAlias" + + if err := validateGetRequest(req); err != nil { + return nil, err + } + authResults := s.authResult(ctx, req.GetId(), action.Read) + if authResults.Error != nil { + return nil, authResults.Error + } + u, err := s.getFromRepo(ctx, req.GetId()) + if err != nil { + return nil, err + } + + outputFields, ok := requests.OutputFields(ctx) + if !ok { + return nil, errors.New(ctx, errors.Internal, op, "no request context found") + } + + outputOpts := make([]handlers.Option, 0, 3) + outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields)) + if outputFields.Has(globals.ScopeField) { + outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) + } + if outputFields.Has(globals.AuthorizedActionsField) { + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, u.GetPublicId(), IdActions).Strings())) + } + + item, err := toProto(ctx, u, outputOpts...) + if err != nil { + return nil, err + } + + return &pbs.GetAliasResponse{Item: item}, nil +} + +// CreateAlias implements the interface pbs.AliasServiceServer. +func (s Service) CreateAlias(ctx context.Context, req *pbs.CreateAliasRequest) (*pbs.CreateAliasResponse, error) { + const op = "aliases.(Service).CreateAlias" + + if err := validateCreateRequest(req); err != nil { + return nil, err + } + authResults := s.authResult(ctx, req.GetItem().GetScopeId(), action.Create) + if authResults.Error != nil { + return nil, authResults.Error + } + a, err := s.createInRepo(ctx, authResults.Scope.GetId(), req.GetItem()) + if err != nil { + return nil, err + } + + outputFields, ok := requests.OutputFields(ctx) + if !ok { + return nil, errors.New(ctx, errors.Internal, op, "no request context found") + } + + outputOpts := make([]handlers.Option, 0, 3) + outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields)) + if outputFields.Has(globals.ScopeField) { + outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) + } + if outputFields.Has(globals.AuthorizedActionsField) { + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, a.GetPublicId(), IdActions).Strings())) + } + + item, err := toProto(ctx, a, outputOpts...) + if err != nil { + return nil, err + } + + return &pbs.CreateAliasResponse{Item: item, Uri: fmt.Sprintf("aliases/%s", item.GetId())}, nil +} + +// UpdateAlias implements the interface pbs.AliasServiceServer. +func (s Service) UpdateAlias(ctx context.Context, req *pbs.UpdateAliasRequest) (*pbs.UpdateAliasResponse, error) { + const op = "aliases.(Service).UpdateAlias" + + if err := validateUpdateRequest(req); err != nil { + return nil, err + } + authResults := s.authResult(ctx, req.GetId(), action.Update) + if authResults.Error != nil { + return nil, authResults.Error + } + u, err := s.updateInRepo(ctx, authResults.Scope.GetId(), req.GetId(), req.GetUpdateMask().GetPaths(), req.GetItem()) + if err != nil { + return nil, err + } + + outputFields, ok := requests.OutputFields(ctx) + if !ok { + return nil, errors.New(ctx, errors.Internal, op, "no request context found") + } + + outputOpts := make([]handlers.Option, 0, 3) + outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields)) + if outputFields.Has(globals.ScopeField) { + outputOpts = append(outputOpts, handlers.WithScope(authResults.Scope)) + } + if outputFields.Has(globals.AuthorizedActionsField) { + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authResults.FetchActionSetForId(ctx, u.GetPublicId(), IdActions).Strings())) + } + + item, err := toProto(ctx, u, outputOpts...) + if err != nil { + return nil, err + } + + return &pbs.UpdateAliasResponse{Item: item}, nil +} + +// DeleteAlias implements the interface pbs.AliasServiceServer. +func (s Service) DeleteAlias(ctx context.Context, req *pbs.DeleteAliasRequest) (*pbs.DeleteAliasResponse, error) { + if err := validateDeleteRequest(req); err != nil { + return nil, err + } + authResults := s.authResult(ctx, req.GetId(), action.Delete) + if authResults.Error != nil { + return nil, authResults.Error + } + _, err := s.deleteFromRepo(ctx, req.GetId()) + if err != nil { + return nil, err + } + return nil, nil +} + +func (s Service) getFromRepo(ctx context.Context, id string) (*target.Alias, error) { + const op = "aliases.(Service).getFromRepo" + repo, err := s.repoFn() + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + g, err := repo.LookupAlias(ctx, id) + if err != nil && !errors.IsNotFoundError(err) { + return nil, errors.Wrap(ctx, err, op) + } + if g == nil { + return nil, errors.New(ctx, errors.InvalidParameter, op, fmt.Sprintf("alias %q not found", id)) + } + return g, err +} + +func (s Service) createInRepo(ctx context.Context, scopeId string, item *pb.Alias) (*target.Alias, error) { + const op = "aliases.(Service).createInRepo" + var opts []target.Option + if item.GetDescription() != nil { + opts = append(opts, target.WithDescription(item.GetDescription().GetValue())) + } + if item.GetName() != nil { + opts = append(opts, target.WithName(item.GetName().GetValue())) + } + if item.GetDestinationId() != nil { + opts = append(opts, target.WithDestinationId(item.GetDestinationId().GetValue())) + } + if item.GetTargetAliasAttributes().GetAuthorizeSessionArguments().GetHostId() != "" { + opts = append(opts, target.WithHostId(item.GetTargetAliasAttributes().GetAuthorizeSessionArguments().GetHostId())) + } + a, err := target.NewAlias(ctx, scopeId, item.GetValue(), opts...) + if err != nil { + return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to build alias for creation: %v.", err) + } + repo, err := s.repoFn() + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + out, err := repo.CreateAlias(ctx, a) + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + if out == nil { + return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to create alias but no error returned from repository.") + } + return out, nil +} + +func (s Service) updateInRepo(ctx context.Context, scopeId, id string, mask []string, item *pb.Alias) (*target.Alias, error) { + const op = "aliases.(Service).updateInRepo" + var opts []target.Option + if item.GetDescription() != nil { + opts = append(opts, target.WithDescription(item.GetDescription().GetValue())) + } + if item.GetName() != nil { + opts = append(opts, target.WithName(item.GetName().GetValue())) + } + if item.GetDestinationId() != nil { + opts = append(opts, target.WithDestinationId(item.GetDestinationId().GetValue())) + } + if item.GetTargetAliasAttributes().GetAuthorizeSessionArguments().GetHostId() != "" { + opts = append(opts, target.WithHostId(item.GetTargetAliasAttributes().GetAuthorizeSessionArguments().GetHostId())) + } + version := item.GetVersion() + g, err := target.NewAlias(ctx, scopeId, item.GetValue(), opts...) + if err != nil { + return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "Unable to build alias for update: %v.", err) + } + g.PublicId = id + dbMask := maskManager.Translate(mask) + if len(dbMask) == 0 { + return nil, handlers.InvalidArgumentErrorf("No valid fields included in the update mask.", map[string]string{"update_mask": "No valid fields provided in the update mask."}) + } + repo, err := s.repoFn() + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + out, rowsUpdated, err := repo.UpdateAlias(ctx, g, version, dbMask) + if err != nil { + return nil, errors.Wrap(ctx, err, op) + } + if rowsUpdated == 0 { + return nil, handlers.NotFoundErrorf("Alias %q doesn't exist or incorrect version provided.", id) + } + return out, nil +} + +func (s Service) deleteFromRepo(ctx context.Context, id string) (bool, error) { + const op = "aliases.(Service).deleteFromRepo" + repo, err := s.repoFn() + if err != nil { + return false, err + } + rows, err := repo.DeleteAlias(ctx, id) + if err != nil { + if errors.IsNotFoundError(err) { + return false, nil + } + return false, errors.Wrap(ctx, err, op, errors.WithMsg("unable to delete alias")) + } + return rows > 0, nil +} + +func (s Service) authResult(ctx context.Context, id string, a action.Type) auth.VerifyResults { + res := auth.VerifyResults{} + iamRepo, err := s.iamRepoFn() + if err != nil { + res.Error = err + return res + } + + var parentId string + opts := []auth.Option{auth.WithType(resource.Alias), auth.WithAction(a)} + switch a { + case action.List, action.Create: + parentId = id + scp, err := iamRepo.LookupScope(ctx, parentId) + if err != nil { + res.Error = err + return res + } + if scp == nil { + res.Error = handlers.NotFoundError() + return res + } + default: + repo, err := s.repoFn() + if err != nil { + res.Error = err + return res + } + grp, err := repo.LookupAlias(ctx, id) + if err != nil { + res.Error = err + return res + } + if grp == nil { + res.Error = handlers.NotFoundError() + return res + } + parentId = grp.GetScopeId() + opts = append(opts, auth.WithId(id)) + } + opts = append(opts, auth.WithScopeId(parentId)) + return auth.Verify(ctx, opts...) +} + +func toProto(ctx context.Context, in *target.Alias, opt ...handlers.Option) (*pb.Alias, error) { + opts := handlers.GetOpts(opt...) + if opts.WithOutputFields == nil { + return nil, handlers.ApiErrorWithCodeAndMessage(codes.Internal, "output fields not found when building alias proto") + } + outputFields := *opts.WithOutputFields + + out := pb.Alias{} + if outputFields.Has(globals.IdField) { + out.Id = in.GetPublicId() + } + if outputFields.Has(globals.ScopeIdField) { + out.ScopeId = in.GetScopeId() + } + if outputFields.Has(globals.NameField) && in.GetName() != "" { + out.Name = wrapperspb.String(in.GetName()) + } + if outputFields.Has(globals.DescriptionField) && in.GetDescription() != "" { + out.Description = wrapperspb.String(in.GetDescription()) + } + if outputFields.Has(globals.ValueField) && in.GetValue() != "" { + out.Value = in.GetValue() + } + if outputFields.Has(globals.CreatedTimeField) { + out.CreatedTime = in.GetCreateTime().GetTimestamp() + } + if outputFields.Has(globals.UpdatedTimeField) { + out.UpdatedTime = in.GetUpdateTime().GetTimestamp() + } + if outputFields.Has(globals.VersionField) { + out.Version = in.GetVersion() + } + if outputFields.Has(globals.ScopeField) { + out.Scope = opts.WithScope + } + if outputFields.Has(globals.AuthorizedActionsField) { + out.AuthorizedActions = opts.WithAuthorizedActions + } + if outputFields.Has(globals.DestinationIdField) && in.GetDestinationId() != "" { + out.DestinationId = wrapperspb.String(in.GetDestinationId()) + } + if outputFields.Has(globals.AttributesField) && in.GetHostId() != "" { + out.Attrs = &pb.Alias_TargetAliasAttributes{ + TargetAliasAttributes: &pb.TargetAliasAttributes{ + AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{ + HostId: in.GetHostId(), + }, + }, + } + } + return &out, nil +} + +// A validateX method should exist for each method above. These methods do not make calls to any backing service but enforce +// requirements on the structure of the request. They verify that: +// - The path passed in is correctly formatted +// - All required parameters are set +// - There are no conflicting parameters provided +func validateGetRequest(req *pbs.GetAliasRequest) error { + return handlers.ValidateGetRequest(handlers.NoopValidatorFn, req, globals.TargetAliasPrefix) +} + +func validateCreateRequest(req *pbs.CreateAliasRequest) error { + return handlers.ValidateCreateRequest(req.GetItem(), func() map[string]string { + badFields := map[string]string{} + if scope.Global.String() != req.GetItem().GetScopeId() { + badFields["scope_id"] = "This field is missing or improperly formatted." + } + if req.GetItem().GetTargetAliasAttributes().GetAuthorizeSessionArguments().GetHostId() != "" && req.GetItem().GetDestinationId().GetValue() == "" { + badFields["destination_id"] = "This field is required when 'attributes.authorize_sesion_arguments.host_id' is specified." + } + return badFields + }) +} + +func validateUpdateRequest(req *pbs.UpdateAliasRequest) error { + return handlers.ValidateUpdateRequest(req, req.GetItem(), func() map[string]string { + badFields := map[string]string{} + if handlers.MaskContains(req.GetUpdateMask().GetPaths(), "value") && req.GetItem().GetValue() == "" { + badFields["value"] = "This field is required." + } + return badFields + }, globals.TargetAliasPrefix) +} + +func validateDeleteRequest(req *pbs.DeleteAliasRequest) error { + return handlers.ValidateDeleteRequest(handlers.NoopValidatorFn, req, globals.TargetAliasPrefix) +} + +func validateListRequest(ctx context.Context, req *pbs.ListAliasesRequest) error { + badFields := map[string]string{} + if !handlers.ValidId(handlers.Id(req.GetScopeId()), scope.Org.Prefix()) && + !handlers.ValidId(handlers.Id(req.GetScopeId()), scope.Project.Prefix()) && + req.GetScopeId() != scope.Global.String() { + badFields["scope_id"] = "Incorrectly formatted identifier." + } + if _, err := handlers.NewFilter(ctx, req.GetFilter()); err != nil { + badFields["filter"] = fmt.Sprintf("This field could not be parsed. %v", err) + } + if len(badFields) > 0 { + return handlers.InvalidArgumentErrorf("Improperly formatted identifier.", badFields) + } + return nil +} + +func newOutputOpts(ctx context.Context, item *target.Alias, scopeInfoMap map[string]*scopes.ScopeInfo, authResults auth.VerifyResults) ([]handlers.Option, bool) { + res := perms.Resource{ + Type: resource.Alias, + } + res.Id = item.GetPublicId() + res.ScopeId = item.GetScopeId() + authorizedActions := authResults.FetchActionSetForId(ctx, item.GetPublicId(), IdActions, auth.WithResource(&res)) + if len(authorizedActions) == 0 { + return nil, false + } + + outputFields := authResults.FetchOutputFields(res, action.List).SelfOrDefaults(authResults.UserId) + outputOpts := make([]handlers.Option, 0, 3) + outputOpts = append(outputOpts, handlers.WithOutputFields(outputFields)) + if outputFields.Has(globals.ScopeField) { + outputOpts = append(outputOpts, handlers.WithScope(scopeInfoMap[item.GetScopeId()])) + } + if outputFields.Has(globals.AuthorizedActionsField) { + outputOpts = append(outputOpts, handlers.WithAuthorizedActions(authorizedActions.Strings())) + } + return outputOpts, true +} diff --git a/internal/daemon/controller/handlers/aliases/alias_service_test.go b/internal/daemon/controller/handlers/aliases/alias_service_test.go new file mode 100644 index 000000000..a38958042 --- /dev/null +++ b/internal/daemon/controller/handlers/aliases/alias_service_test.go @@ -0,0 +1,1280 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package aliases_test + +import ( + "context" + "errors" + "fmt" + "slices" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/hashicorp/boundary/globals" + "github.com/hashicorp/boundary/internal/alias/target" + "github.com/hashicorp/boundary/internal/auth/password" + "github.com/hashicorp/boundary/internal/authtoken" + "github.com/hashicorp/boundary/internal/daemon/controller/auth" + "github.com/hashicorp/boundary/internal/daemon/controller/handlers" + "github.com/hashicorp/boundary/internal/daemon/controller/handlers/aliases" + "github.com/hashicorp/boundary/internal/db" + pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services" + authpb "github.com/hashicorp/boundary/internal/gen/controller/auth" + "github.com/hashicorp/boundary/internal/iam" + "github.com/hashicorp/boundary/internal/kms" + "github.com/hashicorp/boundary/internal/requests" + "github.com/hashicorp/boundary/internal/server" + "github.com/hashicorp/boundary/internal/target/tcp" + "github.com/hashicorp/boundary/internal/types/scope" + pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/aliases" + "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" + "google.golang.org/genproto/protobuf/field_mask" + "google.golang.org/grpc/codes" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var testAuthorizedActions = []string{"no-op", "read", "update", "delete"} + +func TestGet(t *testing.T) { + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, wrap) + iamRepo := iam.TestRepo(t, conn, wrap) + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + + repoFn := func() (*target.Repository, error) { + return target.NewRepository(ctx, rw, rw, kmsCache) + } + _, p := iam.TestScopes(t, iamRepo) + tar := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget") + og := target.TestAlias(t, rw, "test.get", target.WithName("alias name"), target.WithDescription("default"), target.WithDestinationId(tar.GetPublicId()), target.WithHostId("hst_1234567890")) + + toMerge := &pbs.GetAliasRequest{ + Id: og.GetPublicId(), + } + + globalScopeInfo := &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"} + wantAlias := &pb.Alias{ + Id: og.GetPublicId(), + ScopeId: "global", + Scope: globalScopeInfo, + Name: wrapperspb.String(og.GetName()), + Description: wrapperspb.String(og.GetDescription()), + CreatedTime: og.CreateTime.GetTimestamp(), + UpdatedTime: og.UpdateTime.GetTimestamp(), + Value: og.GetValue(), + Version: 1, + DestinationId: wrapperspb.String(og.GetDestinationId()), + Attrs: &pb.Alias_TargetAliasAttributes{ + TargetAliasAttributes: &pb.TargetAliasAttributes{ + AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{ + HostId: og.GetHostId(), + }, + }, + }, + AuthorizedActions: testAuthorizedActions, + } + + cases := []struct { + name string + scopeId string + req *pbs.GetAliasRequest + res *pbs.GetAliasResponse + err error + }{ + { + name: "Get an Existing Alias", + scopeId: og.GetScopeId(), + req: &pbs.GetAliasRequest{Id: og.GetPublicId()}, + res: &pbs.GetAliasResponse{Item: wantAlias}, + }, + { + name: "Get a non existant Alias", + req: &pbs.GetAliasRequest{Id: globals.TargetAliasPrefix + "_DoesntExis"}, + res: nil, + err: handlers.ApiErrorWithCode(codes.NotFound), + }, + { + name: "Wrong id prefix", + req: &pbs.GetAliasRequest{Id: "j_1234567890"}, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "space in id", + req: &pbs.GetAliasRequest{Id: globals.TargetAliasPrefix + "_1 23456789"}, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + req := proto.Clone(toMerge).(*pbs.GetAliasRequest) + proto.Merge(req, tc.req) + + s, err := aliases.NewService(ctx, repoFn, iamRepoFn, 1000) + require.NoError(err, "Couldn't create new alias service.") + + got, gErr := s.GetAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), req) + if tc.err != nil { + require.Error(gErr) + assert.True(errors.Is(gErr, tc.err), "GetAlias(%+v) got error %v, wanted %v", req, gErr, tc.err) + } + assert.Empty(cmp.Diff( + got, + tc.res, + protocmp.Transform(), + cmpopts.SortSlices(func(a, b string) bool { + return a < b + }), + ), "GetAlias(%q) got response\n%q, wanted\n%q", req, got, tc.res) + }) + } +} + +func TestList(t *testing.T) { + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, wrap) + iamRepo := iam.TestRepo(t, conn, wrap) + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + repo, err := target.NewRepository(ctx, rw, rw, kmsCache) + require.NoError(t, err) + repoFn := func() (*target.Repository, error) { + return repo, nil + } + + var wantGlobalAliass []*pb.Alias + for i := 0; i < 10; i++ { + gg := target.TestAlias(t, rw, fmt.Sprintf("test%d.alias", i)) + wantGlobalAliass = append(wantGlobalAliass, &pb.Alias{ + Id: gg.GetPublicId(), + ScopeId: gg.GetScopeId(), + Scope: &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"}, + CreatedTime: gg.GetCreateTime().GetTimestamp(), + UpdatedTime: gg.GetUpdateTime().GetTimestamp(), + Version: 1, + Value: gg.GetValue(), + AuthorizedActions: testAuthorizedActions, + }) + } + + slices.Reverse(wantGlobalAliass) + + cases := []struct { + name string + req *pbs.ListAliasesRequest + res *pbs.ListAliasesResponse + err error + }{ + { + name: "List Global Aliass", + req: &pbs.ListAliasesRequest{ScopeId: "global"}, + res: &pbs.ListAliasesResponse{ + Items: wantGlobalAliass, + EstItemCount: uint32(len(wantGlobalAliass)), + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + }, + }, + { + name: "List global aliass recursively", + req: &pbs.ListAliasesRequest{ScopeId: "global", Recursive: true}, + res: &pbs.ListAliasesResponse{ + Items: wantGlobalAliass, + EstItemCount: uint32(len(wantGlobalAliass)), + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + }, + }, + { + name: "Filter to no aliass", + req: &pbs.ListAliasesRequest{ScopeId: "global", Recursive: true, Filter: `"/item/id"=="doesntmatch"`}, + res: &pbs.ListAliasesResponse{ + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + }, + }, + { + name: "Filter Bad Format", + req: &pbs.ListAliasesRequest{ScopeId: "global", Filter: `"//id/"=="bad"`}, + err: handlers.InvalidArgumentErrorf("bad format", nil), + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + s, err := aliases.NewService(ctx, repoFn, iamRepoFn, 1000) + require.NoError(err, "Couldn't create new alias service.") + + // Test with a non-anon user + got, gErr := s.ListAliases(auth.DisabledAuthTestContext(iamRepoFn, tc.req.GetScopeId()), tc.req) + if tc.err != nil { + require.Error(gErr) + assert.True(errors.Is(gErr, tc.err), "ListAliases(%q) got error %v, wanted %v", tc.req.GetScopeId(), gErr, tc.err) + return + } + require.NoError(gErr) + assert.Empty(cmp.Diff( + got, + tc.res, + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"), + cmpopts.SortSlices(func(a, b string) bool { + return a < b + }), + ), "ListAliass(%q) got response %q, wanted %q", tc.req.GetScopeId(), got, tc.res) + + // Test the anon case + got, gErr = s.ListAliases(auth.DisabledAuthTestContext(iamRepoFn, tc.req.GetScopeId(), auth.WithUserId(globals.AnonymousUserId)), tc.req) + require.NoError(gErr) + assert.Len(got.Items, len(tc.res.Items)) + for _, item := range got.GetItems() { + require.Nil(item.CreatedTime) + require.Nil(item.UpdatedTime) + require.Zero(item.Version) + } + }) + } +} + +func aliasToProto(u *target.Alias, si *scopes.ScopeInfo, authorizedActions []string) *pb.Alias { + pu := &pb.Alias{ + Id: u.GetPublicId(), + Value: u.GetValue(), + ScopeId: u.GetScopeId(), + Scope: si, + CreatedTime: u.GetCreateTime().GetTimestamp(), + UpdatedTime: u.GetUpdateTime().GetTimestamp(), + Version: u.GetVersion(), + AuthorizedActions: testAuthorizedActions, + } + if u.GetName() != "" { + pu.Name = wrapperspb.String(u.GetName()) + } + if u.GetDestinationId() != "" { + pu.DestinationId = wrapperspb.String(u.GetDestinationId()) + } + if u.GetHostId() != "" { + pu.Attrs = &pb.Alias_TargetAliasAttributes{ + TargetAliasAttributes: &pb.TargetAliasAttributes{ + AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{ + HostId: u.GetHostId(), + }, + }, + } + } + if u.GetDescription() != "" { + pu.Description = wrapperspb.String(u.GetDescription()) + } + return pu +} + +func TestListPagination(t *testing.T) { + // Set database read timeout to avoid duplicates in response + oldReadTimeout := globals.RefreshReadLookbackDuration + globals.RefreshReadLookbackDuration = 0 + t.Cleanup(func() { + globals.RefreshReadLookbackDuration = oldReadTimeout + }) + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + sqlDB, err := conn.SqlDB(ctx) + require.NoError(t, err) + wrapper := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, wrapper) + rw := db.New(conn) + + repo, err := target.NewRepository(ctx, rw, rw, kmsCache) + require.NoError(t, err) + repoFn := func() (*target.Repository, error) { + return repo, nil + } + + iamRepo := iam.TestRepo(t, conn, wrapper) + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + tokenRepoFn := func() (*authtoken.Repository, error) { + return authtoken.NewRepository(ctx, rw, rw, kmsCache) + } + serversRepoFn := func() (*server.Repository, error) { + return server.NewRepository(ctx, rw, rw, kmsCache) + } + tokenRepo, err := tokenRepoFn() + require.NoError(t, err) + + // Run analyze to update postgres meta tables + _, err = sqlDB.ExecContext(ctx, "analyze") + require.NoError(t, err) + + authMethod := password.TestAuthMethods(t, conn, "global", 1)[0] + acct := password.TestAccount(t, conn, authMethod.GetPublicId(), "test_user") + u := iam.TestUser(t, iamRepo, "global", iam.WithAccountIds(acct.PublicId)) + // add roles to be able to see all users + allowedRole := iam.TestRole(t, conn, "global") + iam.TestRoleGrant(t, conn, allowedRole.GetPublicId(), "id=*;type=*;actions=*") + iam.TestUserRole(t, conn, allowedRole.GetPublicId(), u.GetPublicId()) + + at, err := tokenRepo.CreateAuthToken(ctx, u, acct.GetPublicId()) + require.NoError(t, err) + + // Test without anon user + requestInfo := authpb.RequestInfo{ + TokenFormat: uint32(auth.AuthTokenTypeBearer), + PublicId: at.GetPublicId(), + Token: at.GetToken(), + } + requestContext := context.WithValue(context.Background(), requests.ContextRequestInformationKey, &requests.RequestContext{}) + ctx = auth.NewVerifierContext(requestContext, iamRepoFn, tokenRepoFn, serversRepoFn, kmsCache, &requestInfo) + + var globalAliases []*pb.Alias + globalScopeInfo := &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"} + var safeToDeleteAlias string + for i := 0; i < 10; i++ { + gg := target.TestAlias(t, rw, fmt.Sprintf("test%d.alias", i)) + globalAliases = append(globalAliases, aliasToProto(gg, globalScopeInfo, testAuthorizedActions)) + safeToDeleteAlias = gg.GetPublicId() + } + slices.Reverse(globalAliases) + + a, err := aliases.NewService(ctx, repoFn, iamRepoFn, 1000) + require.NoError(t, err, "Couldn't create new alias service.") + + // Run analyze to update postgres estimates + _, err = sqlDB.ExecContext(context.Background(), "analyze") + require.NoError(t, err) + + itemCount := uint32(len(globalAliases)) + testPageSize := int((itemCount - 2) / 2) + + // Start paginating, recursively + req := &pbs.ListAliasesRequest{ + ScopeId: "global", + Recursive: true, + Filter: "", + ListToken: "", + PageSize: uint32(testPageSize), + } + got, err := a.ListAliases(ctx, req) + require.NoError(t, err) + require.Len(t, got.GetItems(), testPageSize) + // Compare without comparing the list token + assert.Empty(t, + cmp.Diff( + got, + &pbs.ListAliasesResponse{ + Items: globalAliases[0:testPageSize], + ResponseType: "delta", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + // In addition to the added aliass, there are the aliass added + // by the test setup when specifying the permissions of the + // requester + EstItemCount: itemCount, + }, + protocmp.SortRepeated(func(a, b string) bool { + return strings.Compare(a, b) < 0 + }), + protocmp.Transform(), + protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"), + ), + ) + + // Request second page + req.ListToken = got.ListToken + got, err = a.ListAliases(ctx, req) + require.NoError(t, err) + require.Len(t, got.GetItems(), testPageSize) + // Compare without comparing the list token + assert.Empty(t, + cmp.Diff( + got, + &pbs.ListAliasesResponse{ + Items: globalAliases[testPageSize : testPageSize*2], + ResponseType: "delta", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: itemCount, + }, + protocmp.Transform(), + protocmp.SortRepeated(func(a, b string) bool { + return strings.Compare(a, b) < 0 + }), + protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"), + ), + ) + + // Request rest of results + req.ListToken = got.ListToken + req.PageSize = 10 + got, err = a.ListAliases(ctx, req) + require.NoError(t, err) + require.Len(t, got.GetItems(), 2) + // Compare without comparing the list token + assert.Empty(t, + cmp.Diff( + got, + &pbs.ListAliasesResponse{ + Items: globalAliases[testPageSize*2:], + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: itemCount, + }, + protocmp.Transform(), + protocmp.SortRepeated(func(a, b string) bool { + return strings.Compare(a, b) < 0 + }), + protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"), + ), + ) + + // Update 2 aliass and see them in the refresh + g1 := globalAliases[len(globalAliases)-1] + g1.Description = wrapperspb.String("updated1") + resp1, err := a.UpdateAlias(ctx, &pbs.UpdateAliasRequest{ + Id: g1.GetId(), + Item: &pb.Alias{Description: g1.GetDescription(), Version: g1.GetVersion()}, + UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}}, + }) + require.NoError(t, err) + g1.UpdatedTime = resp1.GetItem().GetUpdatedTime() + g1.Version = resp1.GetItem().GetVersion() + globalAliases = append([]*pb.Alias{g1}, globalAliases[:len(globalAliases)-1]...) + + g2 := globalAliases[len(globalAliases)-1] + g2.Description = wrapperspb.String("updated2") + resp2, err := a.UpdateAlias(ctx, &pbs.UpdateAliasRequest{ + Id: g2.GetId(), + Item: &pb.Alias{Description: g2.GetDescription(), Version: g2.GetVersion()}, + UpdateMask: &field_mask.FieldMask{Paths: []string{"description"}}, + }) + require.NoError(t, err) + g2.UpdatedTime = resp2.GetItem().GetUpdatedTime() + g2.Version = resp2.GetItem().GetVersion() + globalAliases = append([]*pb.Alias{g2}, globalAliases[:len(globalAliases)-1]...) + + // Run analyze to update postgres estimates + _, err = sqlDB.ExecContext(ctx, "analyze") + require.NoError(t, err) + + // Request updated results + req.ListToken = got.ListToken + req.PageSize = 1 + got, err = a.ListAliases(ctx, req) + require.NoError(t, err) + require.Len(t, got.GetItems(), 1) + // Compare without comparing the list token + assert.Empty(t, + cmp.Diff( + got, + &pbs.ListAliasesResponse{ + Items: []*pb.Alias{globalAliases[0]}, + ResponseType: "delta", + SortBy: "updated_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: itemCount, + }, + protocmp.Transform(), + protocmp.SortRepeated(func(a, b string) bool { + return strings.Compare(a, b) < 0 + }), + protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"), + ), + ) + + // Get next page + req.ListToken = got.ListToken + got, err = a.ListAliases(ctx, req) + require.NoError(t, err) + require.Len(t, got.GetItems(), 1) + // Compare without comparing the list token + assert.Empty(t, + cmp.Diff( + got, + &pbs.ListAliasesResponse{ + Items: []*pb.Alias{globalAliases[1]}, + ResponseType: "complete", + SortBy: "updated_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: itemCount, + }, + protocmp.Transform(), + protocmp.SortRepeated(func(a, b string) bool { + return strings.Compare(a, b) < 0 + }), + protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"), + ), + ) + + // Request new page with filter requiring looping + // to fill the page. + req.ListToken = "" + req.PageSize = 1 + req.Filter = fmt.Sprintf(`"/item/id"==%q or "/item/id"==%q`, globalAliases[len(globalAliases)-2].Id, globalAliases[len(globalAliases)-1].Id) + got, err = a.ListAliases(ctx, req) + require.NoError(t, err) + require.Len(t, got.GetItems(), 1) + assert.Empty(t, + cmp.Diff( + got, + &pbs.ListAliasesResponse{ + Items: []*pb.Alias{globalAliases[len(globalAliases)-2]}, + ResponseType: "delta", + SortBy: "created_time", + SortDir: "desc", + // Should be empty again + RemovedIds: nil, + EstItemCount: itemCount, + }, + protocmp.Transform(), + protocmp.SortRepeated(func(a, b string) bool { + return strings.Compare(a, b) < 0 + }), + protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"), + ), + ) + req.ListToken = got.ListToken + // Get the second page + got, err = a.ListAliases(ctx, req) + require.NoError(t, err) + require.Len(t, got.GetItems(), 1) + assert.Empty(t, + cmp.Diff( + got, + &pbs.ListAliasesResponse{ + Items: []*pb.Alias{globalAliases[len(globalAliases)-1]}, + ResponseType: "complete", + SortBy: "created_time", + SortDir: "desc", + RemovedIds: nil, + EstItemCount: itemCount, + }, + protocmp.Transform(), + protocmp.SortRepeated(func(a, b string) bool { + return strings.Compare(a, b) < 0 + }), + protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"), + ), + ) + + _, err = repo.DeleteAlias(ctx, safeToDeleteAlias) + require.NoError(t, err) + req.ListToken = got.ListToken + got, err = a.ListAliases(ctx, req) + require.NoError(t, err) + assert.Empty(t, + cmp.Diff( + got, + &pbs.ListAliasesResponse{ + Items: nil, + ResponseType: "complete", + SortBy: "updated_time", + SortDir: "desc", + RemovedIds: []string{safeToDeleteAlias}, + EstItemCount: itemCount, + }, + protocmp.Transform(), + protocmp.SortRepeated(func(a, b string) bool { + return strings.Compare(a, b) < 0 + }), + protocmp.IgnoreFields(&pbs.ListAliasesResponse{}, "list_token"), + ), + ) +} + +func TestDelete(t *testing.T) { + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, wrap) + iamRepo := iam.TestRepo(t, conn, wrap) + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + + _, p := iam.TestScopes(t, iamRepo) + + repoFn := func() (*target.Repository, error) { + return target.NewRepository(ctx, rw, rw, kmsCache) + } + tar := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget") + og := target.TestAlias(t, rw, "test.delete", target.WithDescription("default"), target.WithDestinationId(tar.GetPublicId()), target.WithHostId("hst_1234567890")) + + s, err := aliases.NewService(context.Background(), repoFn, iamRepoFn, 1000) + require.NoError(t, err, "Error when getting new alias service.") + + cases := []struct { + name string + scopeId string + req *pbs.DeleteAliasRequest + res *pbs.DeleteAliasResponse + err error + }{ + { + name: "Delete an Existing Alias", + scopeId: og.GetScopeId(), + req: &pbs.DeleteAliasRequest{ + Id: og.GetPublicId(), + }, + }, + { + name: "Delete bad alias id", + scopeId: og.GetScopeId(), + req: &pbs.DeleteAliasRequest{ + Id: globals.TargetAliasPrefix + "_doesntexis", + }, + err: handlers.ApiErrorWithCode(codes.NotFound), + }, + { + name: "Bad Alias Id formatting", + scopeId: og.GetScopeId(), + req: &pbs.DeleteAliasRequest{ + Id: "bad_format", + }, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + got, gErr := s.DeleteAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), tc.req) + if tc.err != nil { + require.Error(gErr) + assert.True(errors.Is(gErr, tc.err), "DeleteAlias(%+v) got error %v, wanted %v", tc.req, gErr, tc.err) + } + assert.EqualValuesf(tc.res, got, "DeleteAlias(%+v) got response %q, wanted %q", tc.req, got, tc.res) + }) + } +} + +func TestDelete_twice(t *testing.T) { + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, wrap) + iamRepo := iam.TestRepo(t, conn, wrap) + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + + repoFn := func() (*target.Repository, error) { + return target.NewRepository(ctx, rw, rw, kmsCache) + } + og := target.TestAlias(t, rw, "test.delete", target.WithDescription("default")) + + s, err := aliases.NewService(context.Background(), repoFn, iamRepoFn, 1000) + require.NoError(t, err, "Error when getting new alias service") + scopeId := og.GetScopeId() + req := &pbs.DeleteAliasRequest{ + Id: og.GetPublicId(), + } + ctx = auth.DisabledAuthTestContext(iamRepoFn, scopeId) + _, gErr := s.DeleteAlias(ctx, req) + assert.NoError(t, gErr, "First attempt") + _, gErr = s.DeleteAlias(ctx, req) + assert.Error(t, gErr, "Second attempt") + assert.True(t, errors.Is(gErr, handlers.ApiErrorWithCode(codes.NotFound)), "Expected permission denied for the second delete.") +} + +func TestCreate(t *testing.T) { + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, wrap) + iamRepo := iam.TestRepo(t, conn, wrap) + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + _, p := iam.TestScopes(t, iamRepo) + + repoFn := func() (*target.Repository, error) { + return target.NewRepository(ctx, rw, rw, kmsCache) + } + tar := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget") + al := target.TestAlias(t, rw, "test.duplicated.create", + target.WithName("alias name"), + target.WithDestinationId(tar.GetPublicId())) + + globalScopeInfo := &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"} + + cases := []struct { + name string + req *pbs.CreateAliasRequest + res *pbs.CreateAliasResponse + errContains string + }{ + { + name: "Create a valid Alias", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: scope.Global.String(), + Value: "valid.alias", + }}, + res: &pbs.CreateAliasResponse{ + Uri: fmt.Sprintf("aliases/%s_", globals.TargetAliasPrefix), + Item: &pb.Alias{ + ScopeId: scope.Global.String(), + Scope: globalScopeInfo, + Value: "valid.alias", + Version: 1, + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "Alias to existing target", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: scope.Global.String(), + Value: "target-assigned.valid.alias", + DestinationId: wrapperspb.String(tar.GetPublicId()), + }}, + res: &pbs.CreateAliasResponse{ + Uri: fmt.Sprintf("aliases/%s_", globals.TargetAliasPrefix), + Item: &pb.Alias{ + ScopeId: scope.Global.String(), + Scope: globalScopeInfo, + Value: "target-assigned.valid.alias", + DestinationId: wrapperspb.String(tar.GetPublicId()), + Version: 1, + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "host id with no destination target", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: scope.Global.String(), + Value: "host-id.no-destination.alias", + Attrs: &pb.Alias_TargetAliasAttributes{ + TargetAliasAttributes: &pb.TargetAliasAttributes{ + AuthorizeSessionArguments: &pb.AuthorizeSessionArguments{ + HostId: "hst_1234567890", + }, + }, + }, + }}, + errContains: `This field is required when 'attributes.authorize_sesion_arguments.host_id' is specified.`, + }, + { + name: "Alias to non existing target", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: scope.Global.String(), + Value: "unknowntarget.alias", + DestinationId: wrapperspb.String("ttcp_1234567890"), + }}, + errContains: `target with specified destination id "ttcp_1234567890" was not found`, + }, + { + name: "Duplicate Alias Value", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: scope.Global.String(), + Value: al.GetValue(), + }}, + errContains: `alias value "test.duplicated.create" is already in use`, + }, + { + name: "Duplicate Alias Name", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: scope.Global.String(), + Value: "duplicate.alias.name", + Name: wrapperspb.String(al.GetName()), + }}, + errContains: `name "alias name" is already in use`, + }, + { + name: "must be in global scope", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: p.GetPublicId(), + Value: "must.be.in.global.scope", + }}, + errContains: `{name: "scope_id", desc: "This field is missing or improperly formatted."}`, + }, + { + name: "Can't specify Id", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: scope.Global.String(), + Id: globals.TargetAliasPrefix + "_notallowed", + }}, + res: nil, + errContains: "This is a read only field.", + }, + { + name: "Can't specify Created Time", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: scope.Global.String(), + CreatedTime: timestamppb.Now(), + }}, + res: nil, + errContains: "This is a read only field.", + }, + { + name: "Can't specify Update Time", + req: &pbs.CreateAliasRequest{Item: &pb.Alias{ + ScopeId: scope.Global.String(), + UpdatedTime: timestamppb.Now(), + }}, + res: nil, + errContains: "This is a read only field.", + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + + s, err := aliases.NewService(context.Background(), repoFn, iamRepoFn, 1000) + require.NoError(err, "Error when getting new alias service.") + + got, gErr := s.CreateAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.req.GetItem().GetScopeId()), tc.req) + if tc.errContains != "" { + require.Error(gErr) + assert.ErrorContains(gErr, tc.errContains) + return + } + require.NoError(gErr) + assert.Contains(got.GetUri(), tc.res.Uri) + assert.True(strings.HasPrefix(got.GetItem().GetId(), globals.TargetAliasPrefix+"_")) + // Clear all values which are hard to compare against. + got.Uri, tc.res.Uri = "", "" + got.Item.Id, tc.res.Item.Id = "", "" + got.Item.CreatedTime, got.Item.UpdatedTime, tc.res.Item.CreatedTime, tc.res.Item.UpdatedTime = nil, nil, nil, nil + assert.Empty(cmp.Diff( + got, + tc.res, + protocmp.Transform(), + cmpopts.SortSlices(func(a, b string) bool { + return a < b + }), + ), "CreateAlias(%q) got response %q, wanted %q", tc.req, got, tc.res) + }) + } +} + +func TestUpdate(t *testing.T) { + ctx := context.Background() + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrap := db.TestWrapper(t) + kmsCache := kms.TestKms(t, conn, wrap) + iamRepo := iam.TestRepo(t, conn, wrap) + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + + _, p := iam.TestScopes(t, iamRepo) + tar := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget") + tar2 := tcp.TestTarget(ctx, t, conn, p.GetPublicId(), "testTarget2") + + repoFn := func() (*target.Repository, error) { + return target.NewRepository(ctx, rw, rw, kmsCache) + } + + og := target.TestAlias(t, rw, "default", + target.WithDestinationId(tar.GetPublicId()), + target.WithName("default"), + target.WithDescription("default")) + + var ogVersion uint32 = 1 + + resetAliass := func(version uint32) { + repo, err := repoFn() + require.NoError(t, err, "Couldn't get a new repo") + og, _, err = repo.UpdateAlias(ctx, og, version, []string{"Name", "Description", "DestinationId", "Value"}) + require.NoError(t, err, "Failed to reset the alias") + ogVersion = og.GetVersion() + } + + created := og.GetCreateTime().GetTimestamp().AsTime() + toMerge := &pbs.UpdateAliasRequest{ + Id: og.GetPublicId(), + } + globalScopeInfo := &scopes.ScopeInfo{Id: scope.Global.String(), Type: scope.Global.String(), Name: "global", Description: "Global Scope"} + + tested, err := aliases.NewService(ctx, repoFn, iamRepoFn, 1000) + require.NoError(t, err, "Error creating new service") + cases := []struct { + name string + scopeId string + req *pbs.UpdateAliasRequest + res *pbs.UpdateAliasResponse + err error + }{ + { + name: "Update an Existing Alias", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name", "description"}, + }, + Item: &pb.Alias{ + Name: wrapperspb.String("updated"), + Description: wrapperspb.String("updated"), + }, + }, + res: &pbs.UpdateAliasResponse{ + Item: &pb.Alias{ + Id: og.GetPublicId(), + ScopeId: og.GetScopeId(), + Scope: globalScopeInfo, + Value: "default", + DestinationId: wrapperspb.String(tar.GetPublicId()), + Name: wrapperspb.String("updated"), + Description: wrapperspb.String("updated"), + CreatedTime: og.GetCreateTime().GetTimestamp(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "Multiple Paths in single string", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name,description"}, + }, + Item: &pb.Alias{ + Name: wrapperspb.String("updated"), + Description: wrapperspb.String("updated"), + }, + }, + res: &pbs.UpdateAliasResponse{ + Item: &pb.Alias{ + Id: og.GetPublicId(), + ScopeId: og.GetScopeId(), + Scope: globalScopeInfo, + Value: "default", + DestinationId: wrapperspb.String(tar.GetPublicId()), + Name: wrapperspb.String("updated"), + Description: wrapperspb.String("updated"), + CreatedTime: og.GetCreateTime().GetTimestamp(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "No Update Mask", + req: &pbs.UpdateAliasRequest{ + Item: &pb.Alias{ + Description: wrapperspb.String("updated desc"), + }, + }, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "No Paths in Mask", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{Paths: []string{}}, + Item: &pb.Alias{ + Description: wrapperspb.String("updated desc"), + }, + }, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "Only non-existant paths in Mask", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{Paths: []string{"nonexistant_field"}}, + Item: &pb.Alias{ + Description: wrapperspb.String("updated desc"), + }, + }, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "Unset Name", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name"}, + }, + Item: &pb.Alias{ + Description: wrapperspb.String("ignored"), + }, + }, + res: &pbs.UpdateAliasResponse{ + Item: &pb.Alias{ + Id: og.GetPublicId(), + ScopeId: og.GetScopeId(), + Scope: globalScopeInfo, + Value: "default", + DestinationId: wrapperspb.String(tar.GetPublicId()), + Description: wrapperspb.String("default"), + CreatedTime: og.GetCreateTime().GetTimestamp(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "Update Only Name", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"name"}, + }, + Item: &pb.Alias{ + Name: wrapperspb.String("updated"), + Description: wrapperspb.String("ignored"), + }, + }, + res: &pbs.UpdateAliasResponse{ + Item: &pb.Alias{ + Id: og.GetPublicId(), + Name: wrapperspb.String("updated"), + ScopeId: og.GetScopeId(), + Scope: globalScopeInfo, + Value: "default", + DestinationId: wrapperspb.String(tar.GetPublicId()), + Description: wrapperspb.String("default"), + CreatedTime: og.GetCreateTime().GetTimestamp(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "Update Only value", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"value"}, + }, + Item: &pb.Alias{ + Name: wrapperspb.String("ignored"), + Value: "updated", + }, + }, + res: &pbs.UpdateAliasResponse{ + Item: &pb.Alias{ + Id: og.GetPublicId(), + ScopeId: og.GetScopeId(), + Scope: globalScopeInfo, + Value: "updated", + DestinationId: wrapperspb.String(tar.GetPublicId()), + Name: wrapperspb.String("default"), + Description: wrapperspb.String("default"), + CreatedTime: og.GetCreateTime().GetTimestamp(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "unset value", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"value"}, + }, + Item: &pb.Alias{ + Name: wrapperspb.String("ignored"), + }, + }, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "Update Only destination id", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"destination_id"}, + }, + Item: &pb.Alias{ + Value: "ignored", + DestinationId: wrapperspb.String(tar2.GetPublicId()), + }, + }, + res: &pbs.UpdateAliasResponse{ + Item: &pb.Alias{ + Id: og.GetPublicId(), + ScopeId: og.GetScopeId(), + Scope: globalScopeInfo, + Value: "default", + DestinationId: wrapperspb.String(tar2.GetPublicId()), + Name: wrapperspb.String("default"), + Description: wrapperspb.String("default"), + CreatedTime: og.GetCreateTime().GetTimestamp(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "Unset destination id", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"destination_id"}, + }, + Item: &pb.Alias{ + Value: "ignored", + }, + }, + res: &pbs.UpdateAliasResponse{ + Item: &pb.Alias{ + Id: og.GetPublicId(), + ScopeId: og.GetScopeId(), + Scope: globalScopeInfo, + Value: "default", + Name: wrapperspb.String("default"), + Description: wrapperspb.String("default"), + CreatedTime: og.GetCreateTime().GetTimestamp(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "Update Only Description", + scopeId: og.GetScopeId(), + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"description"}, + }, + Item: &pb.Alias{ + Description: wrapperspb.String("updated"), + }, + }, + res: &pbs.UpdateAliasResponse{ + Item: &pb.Alias{ + Id: og.GetPublicId(), + ScopeId: og.GetScopeId(), + Scope: globalScopeInfo, + Value: "default", + DestinationId: wrapperspb.String(tar.GetPublicId()), + Name: wrapperspb.String("default"), + Description: wrapperspb.String("updated"), + CreatedTime: og.GetCreateTime().GetTimestamp(), + AuthorizedActions: testAuthorizedActions, + }, + }, + }, + { + name: "Update a Non Existing Alias", + req: &pbs.UpdateAliasRequest{ + Id: globals.TargetAliasPrefix + "_DoesntExis", + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"description"}, + }, + Item: &pb.Alias{ + Description: wrapperspb.String("desc"), + }, + }, + err: handlers.ApiErrorWithCode(codes.NotFound), + }, + { + name: "Cant change Id", + req: &pbs.UpdateAliasRequest{ + Id: og.GetPublicId(), + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"id"}, + }, + Item: &pb.Alias{ + Id: globals.TargetAliasPrefix + "_somethinge", + Description: wrapperspb.String("new desc"), + }, + }, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "Cant specify Created Time", + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"created_time"}, + }, + Item: &pb.Alias{ + CreatedTime: timestamppb.Now(), + }, + }, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + { + name: "Cant specify Updated Time", + req: &pbs.UpdateAliasRequest{ + UpdateMask: &field_mask.FieldMask{ + Paths: []string{"updated_time"}, + }, + Item: &pb.Alias{ + UpdatedTime: timestamppb.Now(), + }, + }, + res: nil, + err: handlers.ApiErrorWithCode(codes.InvalidArgument), + }, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + ver := ogVersion + tc.req.Item.Version = ver + + assert, require := assert.New(t), require.New(t) + req := proto.Clone(toMerge).(*pbs.UpdateAliasRequest) + proto.Merge(req, tc.req) + + // Test with bad version (too high, too low) + req.Item.Version = ver + 2 + _, gErr := tested.UpdateAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), req) + require.Error(gErr) + req.Item.Version = ver - 1 + _, gErr = tested.UpdateAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), req) + require.Error(gErr) + req.Item.Version = ver + + got, gErr := tested.UpdateAlias(auth.DisabledAuthTestContext(iamRepoFn, tc.scopeId), req) + if tc.err != nil { + require.Error(gErr) + assert.True(errors.Is(gErr, tc.err), "UpdateAlias(%+v) got error %v, wanted %v", req, gErr, tc.err) + return + } + require.NoError(gErr) + defer resetAliass(got.GetItem().GetVersion()) + + assert.NotNilf(tc.res, "Expected UpdateAlias response to be nil, but was %v", got) + gotUpdateTime := got.GetItem().GetUpdatedTime().AsTime() + // Verify it is a alias updated after it was created + assert.True(gotUpdateTime.After(created), "Updated alias should have been updated after it's creation. Was updated %v, which is after %v", gotUpdateTime, created) + + // Clear all values which are hard to compare against. + got.Item.UpdatedTime, tc.res.Item.UpdatedTime = nil, nil + + assert.Equal(ver+1, got.GetItem().GetVersion()) + tc.res.Item.Version = ver + 1 + assert.Empty(cmp.Diff( + got, + tc.res, + protocmp.Transform(), + cmpopts.SortSlices(func(a, b string) bool { + return a < b + }), + ), "UpdateAlias(%q) got response %q, wanted %q", req, got, tc.res) + }) + } +} diff --git a/internal/daemon/controller/handlers/list_token.go b/internal/daemon/controller/handlers/list_token.go index 8b4acae52..d8dab9328 100644 --- a/internal/daemon/controller/handlers/list_token.go +++ b/internal/daemon/controller/handlers/list_token.go @@ -140,6 +140,8 @@ func ListTokenResourceToResource(rt pbs.ResourceType) resource.Type { switch rt { case pbs.ResourceType_RESOURCE_TYPE_ACCOUNT: return resource.Account + case pbs.ResourceType_RESOURCE_TYPE_ALIAS: + return resource.Alias case pbs.ResourceType_RESOURCE_TYPE_AUTH_METHOD: return resource.AuthMethod case pbs.ResourceType_RESOURCE_TYPE_AUTH_TOKEN: diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index e1dc4cc49..6d96deb11 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -11,6 +11,9 @@ { "name": "controller.api.services.v1.AccountService" }, + { + "name": "controller.api.services.v1.AliasService" + }, { "name": "controller.api.services.v1.AuthMethodService" }, @@ -303,6 +306,168 @@ ] } }, + "/v1/aliases": { + "get": { + "summary": "Lists all Aliases in a specific Scope.", + "operationId": "AliasService_ListAliases", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/controller.api.services.v1.ListAliasesResponse" + } + } + }, + "parameters": [ + { + "name": "scope_id", + "description": "", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "recursive", + "description": "", + "in": "query", + "required": false, + "type": "boolean" + }, + { + "name": "filter", + "description": "", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "list_token", + "description": "An opaque token used to continue an existing iteration or\nrequest updated items. If not specified, pagination\nwill start from the beginning.", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "page_size", + "description": "The maximum size of a page in this iteration.\nIf unset, the default page size configured will be used.\nIf the page_size is greater than the default page configured,\nan error will be returned.", + "in": "query", + "required": false, + "type": "integer", + "format": "int64" + } + ], + "tags": [ + "controller.api.services.v1.AliasService" + ] + }, + "post": { + "summary": "Creates a single Alias in the provided scope.", + "operationId": "AliasService_CreateAlias", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/controller.api.resources.aliases.v1.Alias" + } + } + }, + "parameters": [ + { + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.api.resources.aliases.v1.Alias" + } + } + ], + "tags": [ + "controller.api.services.v1.AliasService" + ] + } + }, + "/v1/aliases/{id}": { + "get": { + "summary": "Gets a single Alias.", + "operationId": "AliasService_GetAlias", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/controller.api.resources.aliases.v1.Alias" + } + } + }, + "parameters": [ + { + "name": "id", + "description": "", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "controller.api.services.v1.AliasService" + ] + }, + "delete": { + "summary": "Deletes an Alias.", + "operationId": "AliasService_DeleteAlias", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/controller.api.services.v1.DeleteAliasResponse" + } + } + }, + "parameters": [ + { + "name": "id", + "description": "", + "in": "path", + "required": true, + "type": "string" + } + ], + "tags": [ + "controller.api.services.v1.AliasService" + ] + }, + "patch": { + "summary": "Updates an Alias.", + "operationId": "AliasService_UpdateAlias", + "responses": { + "200": { + "description": "", + "schema": { + "$ref": "#/definitions/controller.api.resources.aliases.v1.Alias" + } + } + }, + "parameters": [ + { + "name": "id", + "description": "", + "in": "path", + "required": true, + "type": "string" + }, + { + "name": "item", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/controller.api.resources.aliases.v1.Alias" + } + } + ], + "tags": [ + "controller.api.services.v1.AliasService" + ] + } + }, "/v1/auth-methods": { "get": { "summary": "Lists all Auth Methods.", @@ -4641,6 +4806,71 @@ }, "title": "Account contains all fields related to an Account resource" }, + "controller.api.resources.aliases.v1.Alias": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Output only. The ID of the Alias.", + "readOnly": true + }, + "scope_id": { + "type": "string", + "description": "The ID of the scope of which this Alias is a part." + }, + "scope": { + "$ref": "#/definitions/controller.api.resources.scopes.v1.ScopeInfo", + "description": "Output only. Scope information for this Alias.", + "readOnly": true + }, + "name": { + "type": "string", + "description": "Optional user-set name for identification purposes." + }, + "description": { + "type": "string", + "description": "Optional user-set descripton for identification purposes." + }, + "created_time": { + "type": "string", + "format": "date-time", + "description": "Output only. The time this resource was created.", + "readOnly": true + }, + "updated_time": { + "type": "string", + "format": "date-time", + "description": "Output only. The time this resource was last updated.", + "readOnly": true + }, + "version": { + "type": "integer", + "format": "int64", + "description": "Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.\nThe mutation will fail if the version does not match the latest known good version." + }, + "value": { + "type": "string", + "description": "Required value of the alias. This is the value referenced by the user that\nis resolved to the destination id." + }, + "destination_id": { + "type": "string", + "description": "destination_id is the id of the resource that this Alias points to." + }, + "attributes": { + "type": "object", + "description": "The attributes that are applicable for the specific Alias type." + }, + "authorized_actions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Output only. The available actions on this resource for this user.", + "readOnly": true + } + }, + "title": "Alias contains all fields related to an Alias resource" + }, "controller.api.resources.authmethods.v1.AuthMethod": { "type": "object", "properties": { @@ -7479,6 +7709,18 @@ } } }, + "controller.api.services.v1.CreateAliasResponse": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "title": "" + }, + "item": { + "$ref": "#/definitions/controller.api.resources.aliases.v1.Alias" + } + } + }, "controller.api.services.v1.CreateAuthMethodResponse": { "type": "object", "properties": { @@ -7685,6 +7927,9 @@ "controller.api.services.v1.DeleteAccountResponse": { "type": "object" }, + "controller.api.services.v1.DeleteAliasResponse": { + "type": "object" + }, "controller.api.services.v1.DeleteAuthMethodResponse": { "type": "object" }, @@ -7777,6 +8022,14 @@ } } }, + "controller.api.services.v1.GetAliasResponse": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/controller.api.resources.aliases.v1.Alias" + } + } + }, "controller.api.services.v1.GetAuthMethodResponse": { "type": "object", "properties": { @@ -8072,6 +8325,46 @@ } } }, + "controller.api.services.v1.ListAliasesResponse": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/controller.api.resources.aliases.v1.Alias" + } + }, + "response_type": { + "type": "string", + "description": "The type of response, either \"delta\" or \"complete\".\nDelta signifies that this is part of a paginated result\nor an update to a previously completed pagination.\nComplete signifies that it is the last page." + }, + "list_token": { + "type": "string", + "description": "An opaque token used to continue an existing pagination or\nrequest updated items. Use this token in the next list request\nto request the next page." + }, + "sort_by": { + "type": "string", + "description": "The name of the field which the items are sorted by." + }, + "sort_dir": { + "type": "string", + "description": "The direction of the sort, either \"asc\" or \"desc\"." + }, + "removed_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "A list of item IDs that have been removed since they were returned\nas part of a pagination. They should be dropped from any client cache.\nThis may contain items that are not known to the cache, if they were\ncreated and deleted between listings." + }, + "est_item_count": { + "type": "integer", + "format": "int64", + "description": "An estimate at the total items available. This may change during pagination." + } + } + }, "controller.api.services.v1.ListAuthMethodsResponse": { "type": "object", "properties": { @@ -9380,6 +9673,14 @@ } } }, + "controller.api.services.v1.UpdateAliasResponse": { + "type": "object", + "properties": { + "item": { + "$ref": "#/definitions/controller.api.resources.aliases.v1.Alias" + } + } + }, "controller.api.services.v1.UpdateAuthMethodResponse": { "type": "object", "properties": { diff --git a/internal/gen/controller/api/services/alias_service.pb.go b/internal/gen/controller/api/services/alias_service.pb.go new file mode 100644 index 000000000..b784e75bb --- /dev/null +++ b/internal/gen/controller/api/services/alias_service.pb.go @@ -0,0 +1,966 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: controller/api/services/v1/alias_service.proto + +package services + +import ( + _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + aliases "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/aliases" + _ "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions" + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + fieldmaskpb "google.golang.org/protobuf/types/known/fieldmaskpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type GetAliasRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` +} + +func (x *GetAliasRequest) Reset() { + *x = GetAliasRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAliasRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAliasRequest) ProtoMessage() {} + +func (x *GetAliasRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAliasRequest.ProtoReflect.Descriptor instead. +func (*GetAliasRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{0} +} + +func (x *GetAliasRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type GetAliasResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *aliases.Alias `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *GetAliasResponse) Reset() { + *x = GetAliasResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetAliasResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetAliasResponse) ProtoMessage() {} + +func (x *GetAliasResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetAliasResponse.ProtoReflect.Descriptor instead. +func (*GetAliasResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{1} +} + +func (x *GetAliasResponse) GetItem() *aliases.Alias { + if x != nil { + return x.Item + } + return nil +} + +type ListAliasesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ScopeId string `protobuf:"bytes,1,opt,name=scope_id,proto3" json:"scope_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + Recursive bool `protobuf:"varint,2,opt,name=recursive,proto3" json:"recursive,omitempty" class:"public"` // @gotags: `class:"public"` + Filter string `protobuf:"bytes,30,opt,name=filter,proto3" json:"filter,omitempty" class:"sensitive"` // @gotags: `class:"sensitive"` + // An opaque token used to continue an existing iteration or + // request updated items. If not specified, pagination + // will start from the beginning. + ListToken string `protobuf:"bytes,40,opt,name=list_token,proto3" json:"list_token,omitempty" class:"public"` // @gotags: `class:"public"` + // The maximum size of a page in this iteration. + // If unset, the default page size configured will be used. + // If the page_size is greater than the default page configured, + // an error will be returned. + PageSize uint32 `protobuf:"varint,50,opt,name=page_size,proto3" json:"page_size,omitempty" class:"public"` // @gotags: `class:"public"` +} + +func (x *ListAliasesRequest) Reset() { + *x = ListAliasesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListAliasesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListAliasesRequest) ProtoMessage() {} + +func (x *ListAliasesRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListAliasesRequest.ProtoReflect.Descriptor instead. +func (*ListAliasesRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{2} +} + +func (x *ListAliasesRequest) GetScopeId() string { + if x != nil { + return x.ScopeId + } + return "" +} + +func (x *ListAliasesRequest) GetRecursive() bool { + if x != nil { + return x.Recursive + } + return false +} + +func (x *ListAliasesRequest) GetFilter() string { + if x != nil { + return x.Filter + } + return "" +} + +func (x *ListAliasesRequest) GetListToken() string { + if x != nil { + return x.ListToken + } + return "" +} + +func (x *ListAliasesRequest) GetPageSize() uint32 { + if x != nil { + return x.PageSize + } + return 0 +} + +type ListAliasesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Items []*aliases.Alias `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` + // The type of response, either "delta" or "complete". + // Delta signifies that this is part of a paginated result + // or an update to a previously completed pagination. + // Complete signifies that it is the last page. + ResponseType string `protobuf:"bytes,2,opt,name=response_type,proto3" json:"response_type,omitempty" class:"public"` // @gotags: `class:"public"` + // An opaque token used to continue an existing pagination or + // request updated items. Use this token in the next list request + // to request the next page. + ListToken string `protobuf:"bytes,3,opt,name=list_token,proto3" json:"list_token,omitempty" class:"public"` // @gotags: `class:"public"` + // The name of the field which the items are sorted by. + SortBy string `protobuf:"bytes,4,opt,name=sort_by,proto3" json:"sort_by,omitempty" class:"public"` // @gotags: `class:"public"` + // The direction of the sort, either "asc" or "desc". + SortDir string `protobuf:"bytes,5,opt,name=sort_dir,proto3" json:"sort_dir,omitempty" class:"public"` // @gotags: `class:"public"` + // A list of item IDs that have been removed since they were returned + // as part of a pagination. They should be dropped from any client cache. + // This may contain items that are not known to the cache, if they were + // created and deleted between listings. + RemovedIds []string `protobuf:"bytes,6,rep,name=removed_ids,proto3" json:"removed_ids,omitempty" class:"public"` // @gotags: `class:"public"` + // An estimate at the total items available. This may change during pagination. + EstItemCount uint32 `protobuf:"varint,7,opt,name=est_item_count,proto3" json:"est_item_count,omitempty" class:"public"` // @gotags: `class:"public"` +} + +func (x *ListAliasesResponse) Reset() { + *x = ListAliasesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ListAliasesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListAliasesResponse) ProtoMessage() {} + +func (x *ListAliasesResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ListAliasesResponse.ProtoReflect.Descriptor instead. +func (*ListAliasesResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{3} +} + +func (x *ListAliasesResponse) GetItems() []*aliases.Alias { + if x != nil { + return x.Items + } + return nil +} + +func (x *ListAliasesResponse) GetResponseType() string { + if x != nil { + return x.ResponseType + } + return "" +} + +func (x *ListAliasesResponse) GetListToken() string { + if x != nil { + return x.ListToken + } + return "" +} + +func (x *ListAliasesResponse) GetSortBy() string { + if x != nil { + return x.SortBy + } + return "" +} + +func (x *ListAliasesResponse) GetSortDir() string { + if x != nil { + return x.SortDir + } + return "" +} + +func (x *ListAliasesResponse) GetRemovedIds() []string { + if x != nil { + return x.RemovedIds + } + return nil +} + +func (x *ListAliasesResponse) GetEstItemCount() uint32 { + if x != nil { + return x.EstItemCount + } + return 0 +} + +type CreateAliasRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *aliases.Alias `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *CreateAliasRequest) Reset() { + *x = CreateAliasRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateAliasRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAliasRequest) ProtoMessage() {} + +func (x *CreateAliasRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAliasRequest.ProtoReflect.Descriptor instead. +func (*CreateAliasRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{4} +} + +func (x *CreateAliasRequest) GetItem() *aliases.Alias { + if x != nil { + return x.Item + } + return nil +} + +type CreateAliasResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + Item *aliases.Alias `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *CreateAliasResponse) Reset() { + *x = CreateAliasResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateAliasResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateAliasResponse) ProtoMessage() {} + +func (x *CreateAliasResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateAliasResponse.ProtoReflect.Descriptor instead. +func (*CreateAliasResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{5} +} + +func (x *CreateAliasResponse) GetUri() string { + if x != nil { + return x.Uri + } + return "" +} + +func (x *CreateAliasResponse) GetItem() *aliases.Alias { + if x != nil { + return x.Item + } + return nil +} + +type UpdateAliasRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + Item *aliases.Alias `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` + UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,3,opt,name=update_mask,proto3" json:"update_mask,omitempty"` +} + +func (x *UpdateAliasRequest) Reset() { + *x = UpdateAliasRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateAliasRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAliasRequest) ProtoMessage() {} + +func (x *UpdateAliasRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAliasRequest.ProtoReflect.Descriptor instead. +func (*UpdateAliasRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{6} +} + +func (x *UpdateAliasRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *UpdateAliasRequest) GetItem() *aliases.Alias { + if x != nil { + return x.Item + } + return nil +} + +func (x *UpdateAliasRequest) GetUpdateMask() *fieldmaskpb.FieldMask { + if x != nil { + return x.UpdateMask + } + return nil +} + +type UpdateAliasResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *aliases.Alias `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *UpdateAliasResponse) Reset() { + *x = UpdateAliasResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateAliasResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateAliasResponse) ProtoMessage() {} + +func (x *UpdateAliasResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateAliasResponse.ProtoReflect.Descriptor instead. +func (*UpdateAliasResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{7} +} + +func (x *UpdateAliasResponse) GetItem() *aliases.Alias { + if x != nil { + return x.Item + } + return nil +} + +type DeleteAliasRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` +} + +func (x *DeleteAliasRequest) Reset() { + *x = DeleteAliasRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteAliasRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAliasRequest) ProtoMessage() {} + +func (x *DeleteAliasRequest) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAliasRequest.ProtoReflect.Descriptor instead. +func (*DeleteAliasRequest) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{8} +} + +func (x *DeleteAliasRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +type DeleteAliasResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *DeleteAliasResponse) Reset() { + *x = DeleteAliasResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteAliasResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteAliasResponse) ProtoMessage() {} + +func (x *DeleteAliasResponse) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_services_v1_alias_service_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteAliasResponse.ProtoReflect.Descriptor instead. +func (*DeleteAliasResponse) Descriptor() ([]byte, []int) { + return file_controller_api_services_v1_alias_service_proto_rawDescGZIP(), []int{9} +} + +var File_controller_api_services_v1_alias_service_proto protoreflect.FileDescriptor + +var file_controller_api_services_v1_alias_service_proto_rawDesc = []byte{ + 0x0a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x6c, 0x69, + 0x61, 0x73, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x1a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x2f, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x76, + 0x31, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, 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, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, + 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x21, 0x0a, 0x0f, 0x47, 0x65, 0x74, + 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x52, 0x0a, 0x10, + 0x47, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x3e, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x22, 0xa4, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, + 0x5f, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x72, 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x1e, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x73, + 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, + 0x69, 0x73, 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x70, 0x61, + 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x9d, 0x02, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, + 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x40, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x6c, 0x69, 0x73, 0x74, 0x5f, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6c, 0x69, 0x73, + 0x74, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x5f, + 0x62, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x62, + 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x6f, 0x72, 0x74, 0x5f, 0x64, 0x69, 0x72, 0x12, 0x20, 0x0a, + 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0b, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x5f, 0x69, 0x64, 0x73, 0x12, + 0x26, 0x0a, 0x0e, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0e, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x74, 0x65, + 0x6d, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x54, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x67, 0x0a, + 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x3e, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, + 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, + 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xa2, 0x01, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3e, 0x0a, + 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3c, 0x0a, + 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0b, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x22, 0x55, 0x0a, 0x13, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x3e, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x6c, 0x69, 0x61, + 0x73, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x04, 0x69, 0x74, + 0x65, 0x6d, 0x22, 0x24, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x15, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, + 0xf2, 0x06, 0x0a, 0x0c, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x9e, 0x01, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x2b, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, + 0x69, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x37, 0x92, 0x41, 0x16, 0x12, 0x14, 0x47, + 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x41, 0x6c, 0x69, + 0x61, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, + 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, + 0x7d, 0x12, 0xae, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, + 0x73, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x3e, 0x92, 0x41, 0x28, 0x12, 0x26, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, + 0x6c, 0x6c, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, + 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x20, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x2e, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x0d, 0x12, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, + 0x65, 0x73, 0x12, 0xc1, 0x01, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x69, + 0x61, 0x73, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x51, 0x92, 0x41, 0x2f, 0x12, 0x2d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, + 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, + 0x20, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x2e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x3a, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x0b, 0x2f, 0x76, 0x31, 0x2f, 0x61, + 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0xaa, 0x01, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x92, 0x41, 0x13, 0x12, 0x11, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x2e, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x32, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x12, 0x9e, 0x01, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, + 0x69, 0x61, 0x73, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x92, 0x41, 0x13, 0x12, 0x11, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x2e, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x12, 0x2a, 0x10, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x2f, + 0x7b, 0x69, 0x64, 0x7d, 0x42, 0x55, 0xa2, 0xe3, 0x29, 0x04, 0x61, 0x75, 0x74, 0x68, 0x5a, 0x4b, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, + 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_controller_api_services_v1_alias_service_proto_rawDescOnce sync.Once + file_controller_api_services_v1_alias_service_proto_rawDescData = file_controller_api_services_v1_alias_service_proto_rawDesc +) + +func file_controller_api_services_v1_alias_service_proto_rawDescGZIP() []byte { + file_controller_api_services_v1_alias_service_proto_rawDescOnce.Do(func() { + file_controller_api_services_v1_alias_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_api_services_v1_alias_service_proto_rawDescData) + }) + return file_controller_api_services_v1_alias_service_proto_rawDescData +} + +var file_controller_api_services_v1_alias_service_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_controller_api_services_v1_alias_service_proto_goTypes = []interface{}{ + (*GetAliasRequest)(nil), // 0: controller.api.services.v1.GetAliasRequest + (*GetAliasResponse)(nil), // 1: controller.api.services.v1.GetAliasResponse + (*ListAliasesRequest)(nil), // 2: controller.api.services.v1.ListAliasesRequest + (*ListAliasesResponse)(nil), // 3: controller.api.services.v1.ListAliasesResponse + (*CreateAliasRequest)(nil), // 4: controller.api.services.v1.CreateAliasRequest + (*CreateAliasResponse)(nil), // 5: controller.api.services.v1.CreateAliasResponse + (*UpdateAliasRequest)(nil), // 6: controller.api.services.v1.UpdateAliasRequest + (*UpdateAliasResponse)(nil), // 7: controller.api.services.v1.UpdateAliasResponse + (*DeleteAliasRequest)(nil), // 8: controller.api.services.v1.DeleteAliasRequest + (*DeleteAliasResponse)(nil), // 9: controller.api.services.v1.DeleteAliasResponse + (*aliases.Alias)(nil), // 10: controller.api.resources.aliases.v1.Alias + (*fieldmaskpb.FieldMask)(nil), // 11: google.protobuf.FieldMask +} +var file_controller_api_services_v1_alias_service_proto_depIdxs = []int32{ + 10, // 0: controller.api.services.v1.GetAliasResponse.item:type_name -> controller.api.resources.aliases.v1.Alias + 10, // 1: controller.api.services.v1.ListAliasesResponse.items:type_name -> controller.api.resources.aliases.v1.Alias + 10, // 2: controller.api.services.v1.CreateAliasRequest.item:type_name -> controller.api.resources.aliases.v1.Alias + 10, // 3: controller.api.services.v1.CreateAliasResponse.item:type_name -> controller.api.resources.aliases.v1.Alias + 10, // 4: controller.api.services.v1.UpdateAliasRequest.item:type_name -> controller.api.resources.aliases.v1.Alias + 11, // 5: controller.api.services.v1.UpdateAliasRequest.update_mask:type_name -> google.protobuf.FieldMask + 10, // 6: controller.api.services.v1.UpdateAliasResponse.item:type_name -> controller.api.resources.aliases.v1.Alias + 0, // 7: controller.api.services.v1.AliasService.GetAlias:input_type -> controller.api.services.v1.GetAliasRequest + 2, // 8: controller.api.services.v1.AliasService.ListAliases:input_type -> controller.api.services.v1.ListAliasesRequest + 4, // 9: controller.api.services.v1.AliasService.CreateAlias:input_type -> controller.api.services.v1.CreateAliasRequest + 6, // 10: controller.api.services.v1.AliasService.UpdateAlias:input_type -> controller.api.services.v1.UpdateAliasRequest + 8, // 11: controller.api.services.v1.AliasService.DeleteAlias:input_type -> controller.api.services.v1.DeleteAliasRequest + 1, // 12: controller.api.services.v1.AliasService.GetAlias:output_type -> controller.api.services.v1.GetAliasResponse + 3, // 13: controller.api.services.v1.AliasService.ListAliases:output_type -> controller.api.services.v1.ListAliasesResponse + 5, // 14: controller.api.services.v1.AliasService.CreateAlias:output_type -> controller.api.services.v1.CreateAliasResponse + 7, // 15: controller.api.services.v1.AliasService.UpdateAlias:output_type -> controller.api.services.v1.UpdateAliasResponse + 9, // 16: controller.api.services.v1.AliasService.DeleteAlias:output_type -> controller.api.services.v1.DeleteAliasResponse + 12, // [12:17] is the sub-list for method output_type + 7, // [7:12] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_controller_api_services_v1_alias_service_proto_init() } +func file_controller_api_services_v1_alias_service_proto_init() { + if File_controller_api_services_v1_alias_service_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_controller_api_services_v1_alias_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAliasRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_alias_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetAliasResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_alias_service_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListAliasesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_alias_service_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ListAliasesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_alias_service_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateAliasRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_alias_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateAliasResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_alias_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateAliasRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_alias_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateAliasResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_alias_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteAliasRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_services_v1_alias_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteAliasResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_controller_api_services_v1_alias_service_proto_rawDesc, + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_controller_api_services_v1_alias_service_proto_goTypes, + DependencyIndexes: file_controller_api_services_v1_alias_service_proto_depIdxs, + MessageInfos: file_controller_api_services_v1_alias_service_proto_msgTypes, + }.Build() + File_controller_api_services_v1_alias_service_proto = out.File + file_controller_api_services_v1_alias_service_proto_rawDesc = nil + file_controller_api_services_v1_alias_service_proto_goTypes = nil + file_controller_api_services_v1_alias_service_proto_depIdxs = nil +} diff --git a/internal/gen/controller/api/services/alias_service.pb.gw.go b/internal/gen/controller/api/services/alias_service.pb.gw.go new file mode 100644 index 000000000..1ee5044cf --- /dev/null +++ b/internal/gen/controller/api/services/alias_service.pb.gw.go @@ -0,0 +1,642 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: controller/api/services/v1/alias_service.proto + +/* +Package services is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package services + +import ( + "context" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = metadata.Join + +func request_AliasService_GetAlias_0(ctx context.Context, marshaler runtime.Marshaler, client AliasServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetAliasRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := client.GetAlias(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AliasService_GetAlias_0(ctx context.Context, marshaler runtime.Marshaler, server AliasServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetAliasRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := server.GetAlias(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_AliasService_ListAliases_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_AliasService_ListAliases_0(ctx context.Context, marshaler runtime.Marshaler, client AliasServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListAliasesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AliasService_ListAliases_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.ListAliases(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AliasService_ListAliases_0(ctx context.Context, marshaler runtime.Marshaler, server AliasServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq ListAliasesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AliasService_ListAliases_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.ListAliases(ctx, &protoReq) + return msg, metadata, err + +} + +func request_AliasService_CreateAlias_0(ctx context.Context, marshaler runtime.Marshaler, client AliasServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreateAliasRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CreateAlias(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AliasService_CreateAlias_0(ctx context.Context, marshaler runtime.Marshaler, server AliasServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreateAliasRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.CreateAlias(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_AliasService_UpdateAlias_0 = &utilities.DoubleArray{Encoding: map[string]int{"item": 0, "id": 1}, Base: []int{1, 2, 4, 0, 0, 0, 0}, Check: []int{0, 1, 1, 2, 2, 3, 3}} +) + +func request_AliasService_UpdateAlias_0(ctx context.Context, marshaler runtime.Marshaler, client AliasServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateAliasRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Item); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AliasService_UpdateAlias_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateAlias(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AliasService_UpdateAlias_0(ctx context.Context, marshaler runtime.Marshaler, server AliasServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateAliasRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Item); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if protoReq.UpdateMask == nil || len(protoReq.UpdateMask.GetPaths()) == 0 { + if fieldMask, err := runtime.FieldMaskFromRequestBody(newReader(), protoReq.Item); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } else { + protoReq.UpdateMask = fieldMask + } + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AliasService_UpdateAlias_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UpdateAlias(ctx, &protoReq) + return msg, metadata, err + +} + +func request_AliasService_DeleteAlias_0(ctx context.Context, marshaler runtime.Marshaler, client AliasServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteAliasRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := client.DeleteAlias(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AliasService_DeleteAlias_0(ctx context.Context, marshaler runtime.Marshaler, server AliasServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteAliasRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["id"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id") + } + + protoReq.Id, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err) + } + + msg, err := server.DeleteAlias(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterAliasServiceHandlerServer registers the http handlers for service AliasService to "mux". +// UnaryRPC :call AliasServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterAliasServiceHandlerFromEndpoint instead. +func RegisterAliasServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AliasServiceServer) error { + + mux.Handle("GET", pattern_AliasService_GetAlias_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.AliasService/GetAlias", runtime.WithHTTPPathPattern("/v1/aliases/{id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AliasService_GetAlias_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_GetAlias_0(annotatedContext, mux, outboundMarshaler, w, req, response_AliasService_GetAlias_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_AliasService_ListAliases_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.AliasService/ListAliases", runtime.WithHTTPPathPattern("/v1/aliases")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AliasService_ListAliases_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_ListAliases_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_AliasService_CreateAlias_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.AliasService/CreateAlias", runtime.WithHTTPPathPattern("/v1/aliases")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AliasService_CreateAlias_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_CreateAlias_0(annotatedContext, mux, outboundMarshaler, w, req, response_AliasService_CreateAlias_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PATCH", pattern_AliasService_UpdateAlias_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.AliasService/UpdateAlias", runtime.WithHTTPPathPattern("/v1/aliases/{id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AliasService_UpdateAlias_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_UpdateAlias_0(annotatedContext, mux, outboundMarshaler, w, req, response_AliasService_UpdateAlias_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_AliasService_DeleteAlias_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/controller.api.services.v1.AliasService/DeleteAlias", runtime.WithHTTPPathPattern("/v1/aliases/{id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AliasService_DeleteAlias_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_DeleteAlias_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterAliasServiceHandlerFromEndpoint is same as RegisterAliasServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterAliasServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.DialContext(ctx, endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterAliasServiceHandler(ctx, mux, conn) +} + +// RegisterAliasServiceHandler registers the http handlers for service AliasService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterAliasServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterAliasServiceHandlerClient(ctx, mux, NewAliasServiceClient(conn)) +} + +// RegisterAliasServiceHandlerClient registers the http handlers for service AliasService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "AliasServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "AliasServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "AliasServiceClient" to call the correct interceptors. +func RegisterAliasServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client AliasServiceClient) error { + + mux.Handle("GET", pattern_AliasService_GetAlias_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.AliasService/GetAlias", runtime.WithHTTPPathPattern("/v1/aliases/{id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AliasService_GetAlias_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_GetAlias_0(annotatedContext, mux, outboundMarshaler, w, req, response_AliasService_GetAlias_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_AliasService_ListAliases_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.AliasService/ListAliases", runtime.WithHTTPPathPattern("/v1/aliases")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AliasService_ListAliases_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_ListAliases_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_AliasService_CreateAlias_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.AliasService/CreateAlias", runtime.WithHTTPPathPattern("/v1/aliases")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AliasService_CreateAlias_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_CreateAlias_0(annotatedContext, mux, outboundMarshaler, w, req, response_AliasService_CreateAlias_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("PATCH", pattern_AliasService_UpdateAlias_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.AliasService/UpdateAlias", runtime.WithHTTPPathPattern("/v1/aliases/{id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AliasService_UpdateAlias_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_UpdateAlias_0(annotatedContext, mux, outboundMarshaler, w, req, response_AliasService_UpdateAlias_0{resp}, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_AliasService_DeleteAlias_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/controller.api.services.v1.AliasService/DeleteAlias", runtime.WithHTTPPathPattern("/v1/aliases/{id}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AliasService_DeleteAlias_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_AliasService_DeleteAlias_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +type response_AliasService_GetAlias_0 struct { + proto.Message +} + +func (m response_AliasService_GetAlias_0) XXX_ResponseBody() interface{} { + response := m.Message.(*GetAliasResponse) + return response.Item +} + +type response_AliasService_CreateAlias_0 struct { + proto.Message +} + +func (m response_AliasService_CreateAlias_0) XXX_ResponseBody() interface{} { + response := m.Message.(*CreateAliasResponse) + return response.Item +} + +type response_AliasService_UpdateAlias_0 struct { + proto.Message +} + +func (m response_AliasService_UpdateAlias_0) XXX_ResponseBody() interface{} { + response := m.Message.(*UpdateAliasResponse) + return response.Item +} + +var ( + pattern_AliasService_GetAlias_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "aliases", "id"}, "")) + + pattern_AliasService_ListAliases_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "aliases"}, "")) + + pattern_AliasService_CreateAlias_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "aliases"}, "")) + + pattern_AliasService_UpdateAlias_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "aliases", "id"}, "")) + + pattern_AliasService_DeleteAlias_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "aliases", "id"}, "")) +) + +var ( + forward_AliasService_GetAlias_0 = runtime.ForwardResponseMessage + + forward_AliasService_ListAliases_0 = runtime.ForwardResponseMessage + + forward_AliasService_CreateAlias_0 = runtime.ForwardResponseMessage + + forward_AliasService_UpdateAlias_0 = runtime.ForwardResponseMessage + + forward_AliasService_DeleteAlias_0 = runtime.ForwardResponseMessage +) diff --git a/internal/gen/controller/api/services/alias_service_grpc.pb.go b/internal/gen/controller/api/services/alias_service_grpc.pb.go new file mode 100644 index 000000000..0e90d0f67 --- /dev/null +++ b/internal/gen/controller/api/services/alias_service_grpc.pb.go @@ -0,0 +1,306 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: controller/api/services/v1/alias_service.proto + +package services + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + AliasService_GetAlias_FullMethodName = "/controller.api.services.v1.AliasService/GetAlias" + AliasService_ListAliases_FullMethodName = "/controller.api.services.v1.AliasService/ListAliases" + AliasService_CreateAlias_FullMethodName = "/controller.api.services.v1.AliasService/CreateAlias" + AliasService_UpdateAlias_FullMethodName = "/controller.api.services.v1.AliasService/UpdateAlias" + AliasService_DeleteAlias_FullMethodName = "/controller.api.services.v1.AliasService/DeleteAlias" +) + +// AliasServiceClient is the client API for AliasService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type AliasServiceClient interface { + // GetAlias returns a stored Alias if present. The provided request must + // include the id for the Alias be retrieved. If missing, malformed or + // referencing a non existing Alias an error is returned. + GetAlias(ctx context.Context, in *GetAliasRequest, opts ...grpc.CallOption) (*GetAliasResponse, error) + // ListAliases returns a list of stored Aliases which exist inside the + // provided Scope. The request must include the Scope id which + // contains the Aliases being listed. If missing or malformed an error + // is returned. + ListAliases(ctx context.Context, in *ListAliasesRequest, opts ...grpc.CallOption) (*ListAliasesResponse, error) + // CreateAlias creates and stores an Alias in boundary. The provided + // request must include the Scope ID in which the Alias will be + // created. If the Scope ID is missing, malformed, or references a non + // existing resource an error is returned. If a name or login_name is + // provided that is in use in another Alias in the same Scope an + // error is returned. + CreateAlias(ctx context.Context, in *CreateAliasRequest, opts ...grpc.CallOption) (*CreateAliasResponse, error) + // UpdateAlias updates an existing Alias in boundary. The provided Alias + // must not have any read only fields set. The update mask must be included in + // the request and contain at least 1 mutable field. To unset a field's value, + // include the field in the update mask and don't set it in the provided + // Alias. An error is returned if the Alias id is missing or references a + // non-existing resource. An error is also returned if the request attempts + // to update the name or login_name to one that is already in use in the + // containing Scope. + UpdateAlias(ctx context.Context, in *UpdateAliasRequest, opts ...grpc.CallOption) (*UpdateAliasResponse, error) + // DeleteAlias removes an Alias from Boundary. If the provided Alias Id + // is malformed or not provided an error is returned. + DeleteAlias(ctx context.Context, in *DeleteAliasRequest, opts ...grpc.CallOption) (*DeleteAliasResponse, error) +} + +type aliasServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewAliasServiceClient(cc grpc.ClientConnInterface) AliasServiceClient { + return &aliasServiceClient{cc} +} + +func (c *aliasServiceClient) GetAlias(ctx context.Context, in *GetAliasRequest, opts ...grpc.CallOption) (*GetAliasResponse, error) { + out := new(GetAliasResponse) + err := c.cc.Invoke(ctx, AliasService_GetAlias_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aliasServiceClient) ListAliases(ctx context.Context, in *ListAliasesRequest, opts ...grpc.CallOption) (*ListAliasesResponse, error) { + out := new(ListAliasesResponse) + err := c.cc.Invoke(ctx, AliasService_ListAliases_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aliasServiceClient) CreateAlias(ctx context.Context, in *CreateAliasRequest, opts ...grpc.CallOption) (*CreateAliasResponse, error) { + out := new(CreateAliasResponse) + err := c.cc.Invoke(ctx, AliasService_CreateAlias_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aliasServiceClient) UpdateAlias(ctx context.Context, in *UpdateAliasRequest, opts ...grpc.CallOption) (*UpdateAliasResponse, error) { + out := new(UpdateAliasResponse) + err := c.cc.Invoke(ctx, AliasService_UpdateAlias_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *aliasServiceClient) DeleteAlias(ctx context.Context, in *DeleteAliasRequest, opts ...grpc.CallOption) (*DeleteAliasResponse, error) { + out := new(DeleteAliasResponse) + err := c.cc.Invoke(ctx, AliasService_DeleteAlias_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// AliasServiceServer is the server API for AliasService service. +// All implementations must embed UnimplementedAliasServiceServer +// for forward compatibility +type AliasServiceServer interface { + // GetAlias returns a stored Alias if present. The provided request must + // include the id for the Alias be retrieved. If missing, malformed or + // referencing a non existing Alias an error is returned. + GetAlias(context.Context, *GetAliasRequest) (*GetAliasResponse, error) + // ListAliases returns a list of stored Aliases which exist inside the + // provided Scope. The request must include the Scope id which + // contains the Aliases being listed. If missing or malformed an error + // is returned. + ListAliases(context.Context, *ListAliasesRequest) (*ListAliasesResponse, error) + // CreateAlias creates and stores an Alias in boundary. The provided + // request must include the Scope ID in which the Alias will be + // created. If the Scope ID is missing, malformed, or references a non + // existing resource an error is returned. If a name or login_name is + // provided that is in use in another Alias in the same Scope an + // error is returned. + CreateAlias(context.Context, *CreateAliasRequest) (*CreateAliasResponse, error) + // UpdateAlias updates an existing Alias in boundary. The provided Alias + // must not have any read only fields set. The update mask must be included in + // the request and contain at least 1 mutable field. To unset a field's value, + // include the field in the update mask and don't set it in the provided + // Alias. An error is returned if the Alias id is missing or references a + // non-existing resource. An error is also returned if the request attempts + // to update the name or login_name to one that is already in use in the + // containing Scope. + UpdateAlias(context.Context, *UpdateAliasRequest) (*UpdateAliasResponse, error) + // DeleteAlias removes an Alias from Boundary. If the provided Alias Id + // is malformed or not provided an error is returned. + DeleteAlias(context.Context, *DeleteAliasRequest) (*DeleteAliasResponse, error) + mustEmbedUnimplementedAliasServiceServer() +} + +// UnimplementedAliasServiceServer must be embedded to have forward compatible implementations. +type UnimplementedAliasServiceServer struct { +} + +func (UnimplementedAliasServiceServer) GetAlias(context.Context, *GetAliasRequest) (*GetAliasResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetAlias not implemented") +} +func (UnimplementedAliasServiceServer) ListAliases(context.Context, *ListAliasesRequest) (*ListAliasesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ListAliases not implemented") +} +func (UnimplementedAliasServiceServer) CreateAlias(context.Context, *CreateAliasRequest) (*CreateAliasResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateAlias not implemented") +} +func (UnimplementedAliasServiceServer) UpdateAlias(context.Context, *UpdateAliasRequest) (*UpdateAliasResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateAlias not implemented") +} +func (UnimplementedAliasServiceServer) DeleteAlias(context.Context, *DeleteAliasRequest) (*DeleteAliasResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteAlias not implemented") +} +func (UnimplementedAliasServiceServer) mustEmbedUnimplementedAliasServiceServer() {} + +// UnsafeAliasServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to AliasServiceServer will +// result in compilation errors. +type UnsafeAliasServiceServer interface { + mustEmbedUnimplementedAliasServiceServer() +} + +func RegisterAliasServiceServer(s grpc.ServiceRegistrar, srv AliasServiceServer) { + s.RegisterService(&AliasService_ServiceDesc, srv) +} + +func _AliasService_GetAlias_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetAliasRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AliasServiceServer).GetAlias(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AliasService_GetAlias_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AliasServiceServer).GetAlias(ctx, req.(*GetAliasRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AliasService_ListAliases_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListAliasesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AliasServiceServer).ListAliases(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AliasService_ListAliases_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AliasServiceServer).ListAliases(ctx, req.(*ListAliasesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AliasService_CreateAlias_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateAliasRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AliasServiceServer).CreateAlias(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AliasService_CreateAlias_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AliasServiceServer).CreateAlias(ctx, req.(*CreateAliasRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AliasService_UpdateAlias_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateAliasRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AliasServiceServer).UpdateAlias(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AliasService_UpdateAlias_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AliasServiceServer).UpdateAlias(ctx, req.(*UpdateAliasRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AliasService_DeleteAlias_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteAliasRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AliasServiceServer).DeleteAlias(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: AliasService_DeleteAlias_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AliasServiceServer).DeleteAlias(ctx, req.(*DeleteAliasRequest)) + } + return interceptor(ctx, in, info, handler) +} + +// AliasService_ServiceDesc is the grpc.ServiceDesc for AliasService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var AliasService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "controller.api.services.v1.AliasService", + HandlerType: (*AliasServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetAlias", + Handler: _AliasService_GetAlias_Handler, + }, + { + MethodName: "ListAliases", + Handler: _AliasService_ListAliases_Handler, + }, + { + MethodName: "CreateAlias", + Handler: _AliasService_CreateAlias_Handler, + }, + { + MethodName: "UpdateAlias", + Handler: _AliasService_UpdateAlias_Handler, + }, + { + MethodName: "DeleteAlias", + Handler: _AliasService_DeleteAlias_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "controller/api/services/v1/alias_service.proto", +} diff --git a/internal/gen/controller/api/services/list.pb.go b/internal/gen/controller/api/services/list.pb.go index bfcf130cc..46a9ed5e5 100644 --- a/internal/gen/controller/api/services/list.pb.go +++ b/internal/gen/controller/api/services/list.pb.go @@ -50,6 +50,7 @@ const ( ResourceType_RESOURCE_TYPE_USER ResourceType = 18 ResourceType_RESOURCE_TYPE_WORKER ResourceType = 19 ResourceType_RESOURCE_TYPE_POLICY ResourceType = 20 + ResourceType_RESOURCE_TYPE_ALIAS ResourceType = 21 ) // Enum value maps for ResourceType. @@ -76,6 +77,7 @@ var ( 18: "RESOURCE_TYPE_USER", 19: "RESOURCE_TYPE_WORKER", 20: "RESOURCE_TYPE_POLICY", + 21: "RESOURCE_TYPE_ALIAS", } ResourceType_value = map[string]int32{ "RESOURCE_TYPE_UNSPECIFIED": 0, @@ -99,6 +101,7 @@ var ( "RESOURCE_TYPE_USER": 18, "RESOURCE_TYPE_WORKER": 19, "RESOURCE_TYPE_POLICY": 20, + "RESOURCE_TYPE_ALIAS": 21, } ) @@ -567,7 +570,7 @@ var file_controller_api_services_v1_list_proto_rawDesc = []byte{ 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x2a, 0xf4, 0x04, 0x0a, 0x0c, 0x52, 0x65, 0x73, + 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x2a, 0x8d, 0x05, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x52, 0x45, 0x53, 0x4f, @@ -606,13 +609,14 @@ var file_controller_api_services_v1_list_proto_rawDesc = []byte{ 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x10, 0x12, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x57, 0x4f, 0x52, 0x4b, 0x45, 0x52, 0x10, 0x13, 0x12, 0x18, 0x0a, 0x14, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, - 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x10, 0x14, 0x42, - 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, - 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x4f, 0x4c, 0x49, 0x43, 0x59, 0x10, 0x14, 0x12, + 0x17, 0x0a, 0x13, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x41, 0x4c, 0x49, 0x41, 0x53, 0x10, 0x15, 0x42, 0x4d, 0x5a, 0x4b, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x72, 0x79, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, + 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/proto/controller/api/resources/aliases/v1/alias.proto b/internal/proto/controller/api/resources/aliases/v1/alias.proto new file mode 100644 index 000000000..9025f0c82 --- /dev/null +++ b/internal/proto/controller/api/resources/aliases/v1/alias.proto @@ -0,0 +1,113 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +syntax = "proto3"; + +package controller.api.resources.aliases.v1; + +import "controller/api/resources/scopes/v1/scope.proto"; +import "controller/custom_options/v1/options.proto"; +import "google/api/visibility.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; + +option go_package = "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/aliases;aliases"; + +// Alias contains all fields related to an Alias resource +message Alias { + // Output only. The ID of the Alias. + string id = 10; // @gotags: `class:"public" eventstream:"observation"` + + // The ID of the scope of which this Alias is a part. + string scope_id = 20 [json_name = "scope_id"]; // @gotags: `class:"public" eventstream:"observation"` + + // Output only. Scope information for this Alias. + resources.scopes.v1.ScopeInfo scope = 30; + + // Optional user-set name for identification purposes. + google.protobuf.StringValue name = 40 [ + (custom_options.v1.generate_sdk_option) = true, + (custom_options.v1.mask_mapping) = { + this: "name" + that: "Name" + } + ]; // @gotags: `class:"public"` + + // Optional user-set descripton for identification purposes. + google.protobuf.StringValue description = 50 [ + (custom_options.v1.generate_sdk_option) = true, + (custom_options.v1.mask_mapping) = { + this: "description" + that: "Description" + } + ]; // @gotags: `class:"public"` + + // Output only. The time this resource was created. + google.protobuf.Timestamp created_time = 60 [json_name = "created_time"]; // @gotags: `class:"public" eventstream:"observation"` + + // Output only. The time this resource was last updated. + google.protobuf.Timestamp updated_time = 70 [json_name = "updated_time"]; // @gotags: `class:"public" eventstream:"observation"` + + // Version is used in mutation requests, after the initial creation, to ensure this resource has not changed. + // The mutation will fail if the version does not match the latest known good version. + uint32 version = 80; // @gotags: `class:"public"` + + // Required value of the alias. This is the value referenced by the user that + // is resolved to the destination id. + string value = 90 [ + (custom_options.v1.generate_sdk_option) = true, + (custom_options.v1.mask_mapping) = { + this: "value" + that: "Value" + } + ]; // @gotags: `class:"public"` + + // destination_id is the id of the resource that this Alias points to. + google.protobuf.StringValue destination_id = 100 [ + json_name = "destination_id", + (custom_options.v1.generate_sdk_option) = true, + (custom_options.v1.mask_mapping) = { + this: "destination_id" + that: "DestinationId" + } + ]; // @gotags: `class:"public" eventstream:"observation"` + + oneof attrs { + // The attributes that are applicable for the specific Alias type. + google.protobuf.Struct attributes = 110 [ + (custom_options.v1.generate_sdk_option) = true, + (custom_options.v1.subtype) = "default" + ]; + TargetAliasAttributes target_alias_attributes = 101 [ + (google.api.field_visibility).restriction = "INTERNAL", + (custom_options.v1.generate_sdk_option) = true, + (custom_options.v1.subtype) = "target" + ]; + } + + // Output only. The available actions on this resource for this user. + repeated string authorized_actions = 300 [json_name = "authorized_actions"]; // @gotags: `class:"public"` +} + +// Attributes associated only with Aliases with type "target". +message TargetAliasAttributes { + AuthorizeSessionArguments authorize_session_arguments = 1 [json_name = "authorize_session_arguments"]; // @gotags: `class:"public"` +} + +message AuthorizeSessionArguments { + // host_id is the id of the host that the session will be authorized for. + // When specified authorizing a session using this alias will have the same + // effect of authorizing a session to the aliase's destination_id and passing + // in this value through the -host-id flag. If the host-id flag is also + // specified when calling authorize-session an error will be returned unless + // the provided host-id matches this value. + string host_id = 100 [ + json_name = "login_name", + (custom_options.v1.generate_sdk_option) = true, + (custom_options.v1.mask_mapping) = { + this: "attributes.authorize_session_arguments.host_id" + that: "HostId" + } + ]; // @gotags: `class:"public"` +} diff --git a/internal/proto/controller/api/services/v1/alias_service.proto b/internal/proto/controller/api/services/v1/alias_service.proto new file mode 100644 index 000000000..1a287992d --- /dev/null +++ b/internal/proto/controller/api/services/v1/alias_service.proto @@ -0,0 +1,158 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +syntax = "proto3"; + +package controller.api.services.v1; + +import "controller/api/resources/aliases/v1/alias.proto"; +import "controller/custom_options/v1/options.proto"; +import "google/api/annotations.proto"; +import "google/protobuf/field_mask.proto"; +import "protoc-gen-openapiv2/options/annotations.proto"; + +option go_package = "github.com/hashicorp/boundary/internal/gen/controller/api/services;services"; +option (custom_options.v1.domain) = "auth"; + +service AliasService { + // GetAlias returns a stored Alias if present. The provided request must + // include the id for the Alias be retrieved. If missing, malformed or + // referencing a non existing Alias an error is returned. + rpc GetAlias(GetAliasRequest) returns (GetAliasResponse) { + option (google.api.http) = { + get: "/v1/aliases/{id}" + response_body: "item" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {summary: "Gets a single Alias."}; + } + + // ListAliases returns a list of stored Aliases which exist inside the + // provided Scope. The request must include the Scope id which + // contains the Aliases being listed. If missing or malformed an error + // is returned. + rpc ListAliases(ListAliasesRequest) returns (ListAliasesResponse) { + option (google.api.http) = {get: "/v1/aliases"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {summary: "Lists all Aliases in a specific Scope."}; + } + + // CreateAlias creates and stores an Alias in boundary. The provided + // request must include the Scope ID in which the Alias will be + // created. If the Scope ID is missing, malformed, or references a non + // existing resource an error is returned. If a name or login_name is + // provided that is in use in another Alias in the same Scope an + // error is returned. + rpc CreateAlias(CreateAliasRequest) returns (CreateAliasResponse) { + option (google.api.http) = { + post: "/v1/aliases" + body: "item" + response_body: "item" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {summary: "Creates a single Alias in the provided scope."}; + } + + // UpdateAlias updates an existing Alias in boundary. The provided Alias + // must not have any read only fields set. The update mask must be included in + // the request and contain at least 1 mutable field. To unset a field's value, + // include the field in the update mask and don't set it in the provided + // Alias. An error is returned if the Alias id is missing or references a + // non-existing resource. An error is also returned if the request attempts + // to update the name or login_name to one that is already in use in the + // containing Scope. + rpc UpdateAlias(UpdateAliasRequest) returns (UpdateAliasResponse) { + option (google.api.http) = { + patch: "/v1/aliases/{id}" + body: "item" + response_body: "item" + }; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {summary: "Updates an Alias."}; + } + + // DeleteAlias removes an Alias from Boundary. If the provided Alias Id + // is malformed or not provided an error is returned. + rpc DeleteAlias(DeleteAliasRequest) returns (DeleteAliasResponse) { + option (google.api.http) = {delete: "/v1/aliases/{id}"}; + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = {summary: "Deletes an Alias."}; + } +} + +message GetAliasRequest { + string id = 1; // @gotags: `class:"public" eventstream:"observation"` +} + +message GetAliasResponse { + resources.aliases.v1.Alias item = 1; +} + +message ListAliasesRequest { + string scope_id = 1 [json_name = "scope_id"]; // @gotags: `class:"public" eventstream:"observation"` + + bool recursive = 2; // @gotags: `class:"public"` + + string filter = 30 [json_name = "filter"]; // @gotags: `class:"sensitive"` + + // An opaque token used to continue an existing iteration or + // request updated items. If not specified, pagination + // will start from the beginning. + string list_token = 40 [json_name = "list_token"]; // @gotags: `class:"public"` + + // The maximum size of a page in this iteration. + // If unset, the default page size configured will be used. + // If the page_size is greater than the default page configured, + // an error will be returned. + uint32 page_size = 50 [json_name = "page_size"]; // @gotags: `class:"public"` +} + +message ListAliasesResponse { + repeated resources.aliases.v1.Alias items = 1; + + // The type of response, either "delta" or "complete". + // Delta signifies that this is part of a paginated result + // or an update to a previously completed pagination. + // Complete signifies that it is the last page. + string response_type = 2 [json_name = "response_type"]; // @gotags: `class:"public"` + + // An opaque token used to continue an existing pagination or + // request updated items. Use this token in the next list request + // to request the next page. + string list_token = 3 [json_name = "list_token"]; // @gotags: `class:"public"` + + // The name of the field which the items are sorted by. + string sort_by = 4 [json_name = "sort_by"]; // @gotags: `class:"public"` + + // The direction of the sort, either "asc" or "desc". + string sort_dir = 5 [json_name = "sort_dir"]; // @gotags: `class:"public"` + + // A list of item IDs that have been removed since they were returned + // as part of a pagination. They should be dropped from any client cache. + // This may contain items that are not known to the cache, if they were + // created and deleted between listings. + repeated string removed_ids = 6 [json_name = "removed_ids"]; // @gotags: `class:"public"` + + // An estimate at the total items available. This may change during pagination. + uint32 est_item_count = 7 [json_name = "est_item_count"]; // @gotags: `class:"public"` +} + +message CreateAliasRequest { + resources.aliases.v1.Alias item = 1; +} + +message CreateAliasResponse { + string uri = 1; // @gotags: `class:"public" eventstream:"observation"` + resources.aliases.v1.Alias item = 2; +} + +message UpdateAliasRequest { + string id = 1; // @gotags: `class:"public" eventstream:"observation"` + resources.aliases.v1.Alias item = 2; + google.protobuf.FieldMask update_mask = 3 [json_name = "update_mask"]; +} + +message UpdateAliasResponse { + resources.aliases.v1.Alias item = 1; +} + +message DeleteAliasRequest { + string id = 1; // @gotags: `class:"public" eventstream:"observation"` +} + +message DeleteAliasResponse {} diff --git a/internal/proto/controller/api/services/v1/list.proto b/internal/proto/controller/api/services/v1/list.proto index db1644bb8..784fd7964 100644 --- a/internal/proto/controller/api/services/v1/list.proto +++ b/internal/proto/controller/api/services/v1/list.proto @@ -110,4 +110,5 @@ enum ResourceType { RESOURCE_TYPE_USER = 18; RESOURCE_TYPE_WORKER = 19; RESOURCE_TYPE_POLICY = 20; + RESOURCE_TYPE_ALIAS = 21; } diff --git a/internal/proto/controller/storage/alias/target/store/v1/alias.proto b/internal/proto/controller/storage/alias/target/store/v1/alias.proto index 75e6d545f..339fd250b 100644 --- a/internal/proto/controller/storage/alias/target/store/v1/alias.proto +++ b/internal/proto/controller/storage/alias/target/store/v1/alias.proto @@ -5,6 +5,7 @@ syntax = "proto3"; package controller.storage.alias.target.store.v1; +import "controller/custom_options/v1/options.proto"; import "controller/storage/timestamp/v1/timestamp.proto"; option go_package = "github.com/hashicorp/boundary/internal/alias/target/store;store"; @@ -28,11 +29,17 @@ message Alias { // name is optional // @inject_tag: `gorm:"default:null"` - string name = 5; + string name = 5 [(custom_options.v1.mask_mapping) = { + this: "Name" + that: "name" + }]; // description is optional. // @inject_tag: `gorm:"default:null"` - string description = 6; + string description = 6 [(custom_options.v1.mask_mapping) = { + this: "Description" + that: "description" + }]; // version allows optimistic locking of the resource // @inject_tag: `gorm:"default:null"` @@ -40,12 +47,18 @@ message Alias { // value is required and is the value of the value. // @inject_tag: `gorm:"not_null"` - string value = 8; + string value = 8 [(custom_options.v1.mask_mapping) = { + this: "Value" + that: "value" + }]; // destination_id is optional and is the ID of the target this alias points // to. // @inject_tag: `gorm:"default:null"` - string destination_id = 9; + string destination_id = 9 [(custom_options.v1.mask_mapping) = { + this: "DestinationId" + that: "destination_id" + }]; // host_id is optional and can only be set if destination_id is also set. // The value of this field is used when performing an authorize-session @@ -55,5 +68,8 @@ message Alias { // case then the authorize-session action will return an error when using // this alias. // @inject_tag: `gorm:"default:null"` - string host_id = 10; + string host_id = 10 [(custom_options.v1.mask_mapping) = { + this: "HostId" + that: "attributes.authorize_session_arguments.host_id" + }]; } diff --git a/internal/tests/api/aliases/alias_test.go b/internal/tests/api/aliases/alias_test.go new file mode 100644 index 000000000..231740669 --- /dev/null +++ b/internal/tests/api/aliases/alias_test.go @@ -0,0 +1,172 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package aliases_test + +import ( + "fmt" + "net/http" + "testing" + + "github.com/hashicorp/boundary/api" + "github.com/hashicorp/boundary/api/aliases" + "github.com/hashicorp/boundary/globals" + "github.com/hashicorp/boundary/internal/daemon/controller" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestList(t *testing.T) { + assert, require := assert.New(t), require.New(t) + tc := controller.NewTestController(t, nil) + defer tc.Shutdown() + + scopeId := "global" + + client := tc.Client() + require.NotNil(client) + token := tc.Token() + require.NotNil(token) + client.SetToken(token.Token) + + aliasClient := aliases.NewClient(client) + + lr, err := aliasClient.List(tc.Context(), scopeId) + require.NoError(err) + expected := lr.Items + assert.Len(expected, 0) + + cr, err := aliasClient.Create(tc.Context(), scopeId, aliases.WithValue("alias0")) + require.NoError(err) + require.NotNil(cr) + expected = append(expected, cr.Item) + + ulResult, err := aliasClient.List(tc.Context(), scopeId) + require.NoError(err) + assert.ElementsMatch(comparableSlice(expected[:1]), comparableSlice(ulResult.Items)) + + for i := 1; i < 10; i++ { + newAcctResult, err := aliasClient.Create(tc.Context(), scopeId, aliases.WithValue(fmt.Sprintf("alias%d", i))) + require.NoError(err) + expected = append(expected, newAcctResult.Item) + } + ulResult, err = aliasClient.List(tc.Context(), scopeId) + require.NoError(err) + assert.ElementsMatch(comparableSlice(expected), comparableSlice(ulResult.Items)) + + filterItem := expected[3] + + ulResult, err = aliasClient.List(tc.Context(), scopeId, aliases.WithFilter(fmt.Sprintf(`"/item/value"==%q`, filterItem.Value))) + require.NoError(err) + require.Len(ulResult.Items, 1) + assert.Equal(filterItem.Id, ulResult.Items[0].Id) +} + +func comparableSlice(in []*aliases.Alias) []aliases.Alias { + var filtered []aliases.Alias + for _, i := range in { + p := aliases.Alias{ + Id: i.Id, + Name: i.Name, + Description: i.Description, + CreatedTime: i.CreatedTime, + UpdatedTime: i.UpdatedTime, + Attributes: i.Attributes, + } + filtered = append(filtered, p) + } + return filtered +} + +func TestCrud(t *testing.T) { + assert, require := assert.New(t), require.New(t) + tc := controller.NewTestController(t, nil) + defer tc.Shutdown() + + scopeId := "global" + + client := tc.Client() + token := tc.Token() + client.SetToken(token.Token) + aliasClient := aliases.NewClient(client) + + checkAlias := func(step string, u *aliases.Alias, err error, wantedName string, wantedVersion uint32) { + assert.NoError(err, step) + require.NotNil(u, "returned no resource", step) + gotValue := "" + if u.Value != "" { + gotValue = u.Value + } + assert.Equal(wantedName, gotValue, step) + assert.EqualValues(wantedVersion, u.Version) + } + + u, err := aliasClient.Create(tc.Context(), scopeId, aliases.WithValue("alias.value")) + checkAlias("create", u.Item, err, "alias.value", 1) + + u, err = aliasClient.Read(tc.Context(), u.Item.Id) + checkAlias("read", u.Item, err, "alias.value", 1) + + u, err = aliasClient.Update(tc.Context(), u.Item.Id, u.Item.Version, aliases.WithValue("bar")) + checkAlias("update", u.Item, err, "bar", 2) + + _, err = aliasClient.Delete(tc.Context(), u.Item.Id) + require.NoError(err) +} + +func TestErrors(t *testing.T) { + assert, require := assert.New(t), require.New(t) + tc := controller.NewTestController(t, nil) + defer tc.Shutdown() + + scopeId := "global" + + client := tc.Client() + token := tc.Token() + client.SetToken(token.Token) + aliasClient := aliases.NewClient(client) + + u, err := aliasClient.Create(tc.Context(), scopeId, aliases.WithValue("first")) + require.NoError(err) + assert.NotNil(u) + + // A malformed id is processed as the id and not a different path to the api. + _, err = aliasClient.Read(tc.Context(), fmt.Sprintf("%s/../", u.Item.Id)) + require.Error(err) + apiErr := api.AsServerError(err) + require.NotNil(apiErr) + assert.EqualValues(http.StatusBadRequest, apiErr.Response().StatusCode()) + require.Len(apiErr.Details.RequestFields, 1) + assert.Equal(apiErr.Details.RequestFields[0].Name, "id") + + // Updating the wrong version should fail. + _, err = aliasClient.Update(tc.Context(), u.Item.Id, 73, aliases.WithValue("anything")) + require.Error(err) + apiErr = api.AsServerError(err) + require.NotNil(apiErr) + assert.EqualValues(http.StatusNotFound, apiErr.Response().StatusCode()) + + // Create another resource with the same name. + _, err = aliasClient.Create(tc.Context(), scopeId, aliases.WithValue("first")) + require.Error(err) + apiErr = api.AsServerError(err) + require.NotNil(apiErr) + + _, err = aliasClient.Read(tc.Context(), globals.TargetAliasPrefix+"_doesntexis") + require.Error(err) + apiErr = api.AsServerError(err) + require.NotNil(apiErr) + assert.EqualValues(http.StatusNotFound, apiErr.Response().StatusCode()) + + _, err = aliasClient.Read(tc.Context(), "invalid id") + require.Error(err) + apiErr = api.AsServerError(err) + require.NotNil(apiErr) + assert.EqualValues(http.StatusBadRequest, apiErr.Response().StatusCode()) + + _, err = aliasClient.Update(tc.Context(), u.Item.Id, u.Item.Version) + require.Error(err) + apiErr = api.AsServerError(err) + require.NotNil(apiErr) + assert.EqualValues(http.StatusBadRequest, apiErr.Response().StatusCode()) +} diff --git a/sdk/pbs/controller/api/resources/aliases/alias.pb.go b/sdk/pbs/controller/api/resources/aliases/alias.pb.go new file mode 100644 index 000000000..5d14b16f1 --- /dev/null +++ b/sdk/pbs/controller/api/resources/aliases/alias.pb.go @@ -0,0 +1,524 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: controller/api/resources/aliases/v1/alias.proto + +package aliases + +import ( + scopes "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes" + _ "github.com/hashicorp/boundary/sdk/pbs/controller/protooptions" + _ "google.golang.org/genproto/googleapis/api/visibility" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" + timestamppb "google.golang.org/protobuf/types/known/timestamppb" + wrapperspb "google.golang.org/protobuf/types/known/wrapperspb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Alias contains all fields related to an Alias resource +type Alias struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Output only. The ID of the Alias. + Id string `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // The ID of the scope of which this Alias is a part. + ScopeId string `protobuf:"bytes,20,opt,name=scope_id,proto3" json:"scope_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // Output only. Scope information for this Alias. + Scope *scopes.ScopeInfo `protobuf:"bytes,30,opt,name=scope,proto3" json:"scope,omitempty"` + // Optional user-set name for identification purposes. + Name *wrapperspb.StringValue `protobuf:"bytes,40,opt,name=name,proto3" json:"name,omitempty" class:"public"` // @gotags: `class:"public"` + // Optional user-set descripton for identification purposes. + Description *wrapperspb.StringValue `protobuf:"bytes,50,opt,name=description,proto3" json:"description,omitempty" class:"public"` // @gotags: `class:"public"` + // Output only. The time this resource was created. + CreatedTime *timestamppb.Timestamp `protobuf:"bytes,60,opt,name=created_time,proto3" json:"created_time,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // Output only. The time this resource was last updated. + UpdatedTime *timestamppb.Timestamp `protobuf:"bytes,70,opt,name=updated_time,proto3" json:"updated_time,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // Version is used in mutation requests, after the initial creation, to ensure this resource has not changed. + // The mutation will fail if the version does not match the latest known good version. + Version uint32 `protobuf:"varint,80,opt,name=version,proto3" json:"version,omitempty" class:"public"` // @gotags: `class:"public"` + // Required value of the alias. This is the value referenced by the user that + // is resolved to the destination id. + Value string `protobuf:"bytes,90,opt,name=value,proto3" json:"value,omitempty" class:"public"` // @gotags: `class:"public"` + // destination_id is the id of the resource that this Alias points to. + DestinationId *wrapperspb.StringValue `protobuf:"bytes,100,opt,name=destination_id,proto3" json:"destination_id,omitempty" class:"public" eventstream:"observation"` // @gotags: `class:"public" eventstream:"observation"` + // Types that are assignable to Attrs: + // + // *Alias_Attributes + // *Alias_TargetAliasAttributes + Attrs isAlias_Attrs `protobuf_oneof:"attrs"` + // 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" class:"public"` // @gotags: `class:"public"` +} + +func (x *Alias) Reset() { + *x = Alias{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_resources_aliases_v1_alias_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Alias) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Alias) ProtoMessage() {} + +func (x *Alias) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_resources_aliases_v1_alias_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Alias.ProtoReflect.Descriptor instead. +func (*Alias) Descriptor() ([]byte, []int) { + return file_controller_api_resources_aliases_v1_alias_proto_rawDescGZIP(), []int{0} +} + +func (x *Alias) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Alias) GetScopeId() string { + if x != nil { + return x.ScopeId + } + return "" +} + +func (x *Alias) GetScope() *scopes.ScopeInfo { + if x != nil { + return x.Scope + } + return nil +} + +func (x *Alias) GetName() *wrapperspb.StringValue { + if x != nil { + return x.Name + } + return nil +} + +func (x *Alias) GetDescription() *wrapperspb.StringValue { + if x != nil { + return x.Description + } + return nil +} + +func (x *Alias) GetCreatedTime() *timestamppb.Timestamp { + if x != nil { + return x.CreatedTime + } + return nil +} + +func (x *Alias) GetUpdatedTime() *timestamppb.Timestamp { + if x != nil { + return x.UpdatedTime + } + return nil +} + +func (x *Alias) GetVersion() uint32 { + if x != nil { + return x.Version + } + return 0 +} + +func (x *Alias) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +func (x *Alias) GetDestinationId() *wrapperspb.StringValue { + if x != nil { + return x.DestinationId + } + return nil +} + +func (m *Alias) GetAttrs() isAlias_Attrs { + if m != nil { + return m.Attrs + } + return nil +} + +func (x *Alias) GetAttributes() *structpb.Struct { + if x, ok := x.GetAttrs().(*Alias_Attributes); ok { + return x.Attributes + } + return nil +} + +func (x *Alias) GetTargetAliasAttributes() *TargetAliasAttributes { + if x, ok := x.GetAttrs().(*Alias_TargetAliasAttributes); ok { + return x.TargetAliasAttributes + } + return nil +} + +func (x *Alias) GetAuthorizedActions() []string { + if x != nil { + return x.AuthorizedActions + } + return nil +} + +type isAlias_Attrs interface { + isAlias_Attrs() +} + +type Alias_Attributes struct { + // The attributes that are applicable for the specific Alias type. + Attributes *structpb.Struct `protobuf:"bytes,110,opt,name=attributes,proto3,oneof"` +} + +type Alias_TargetAliasAttributes struct { + TargetAliasAttributes *TargetAliasAttributes `protobuf:"bytes,101,opt,name=target_alias_attributes,json=targetAliasAttributes,proto3,oneof"` +} + +func (*Alias_Attributes) isAlias_Attrs() {} + +func (*Alias_TargetAliasAttributes) isAlias_Attrs() {} + +// Attributes associated only with Aliases with type "target". +type TargetAliasAttributes struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AuthorizeSessionArguments *AuthorizeSessionArguments `protobuf:"bytes,1,opt,name=authorize_session_arguments,proto3" json:"authorize_session_arguments,omitempty" class:"public"` // @gotags: `class:"public"` +} + +func (x *TargetAliasAttributes) Reset() { + *x = TargetAliasAttributes{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_resources_aliases_v1_alias_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TargetAliasAttributes) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TargetAliasAttributes) ProtoMessage() {} + +func (x *TargetAliasAttributes) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_resources_aliases_v1_alias_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TargetAliasAttributes.ProtoReflect.Descriptor instead. +func (*TargetAliasAttributes) Descriptor() ([]byte, []int) { + return file_controller_api_resources_aliases_v1_alias_proto_rawDescGZIP(), []int{1} +} + +func (x *TargetAliasAttributes) GetAuthorizeSessionArguments() *AuthorizeSessionArguments { + if x != nil { + return x.AuthorizeSessionArguments + } + return nil +} + +type AuthorizeSessionArguments struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // host_id is the id of the host that the session will be authorized for. + // When specified authorizing a session using this alias will have the same + // effect of authorizing a session to the aliase's destination_id and passing + // in this value through the -host-id flag. If the host-id flag is also + // specified when calling authorize-session an error will be returned unless + // the provided host-id matches this value. + HostId string `protobuf:"bytes,100,opt,name=host_id,json=login_name,proto3" json:"host_id,omitempty" class:"public"` // @gotags: `class:"public"` +} + +func (x *AuthorizeSessionArguments) Reset() { + *x = AuthorizeSessionArguments{} + if protoimpl.UnsafeEnabled { + mi := &file_controller_api_resources_aliases_v1_alias_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AuthorizeSessionArguments) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AuthorizeSessionArguments) ProtoMessage() {} + +func (x *AuthorizeSessionArguments) ProtoReflect() protoreflect.Message { + mi := &file_controller_api_resources_aliases_v1_alias_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AuthorizeSessionArguments.ProtoReflect.Descriptor instead. +func (*AuthorizeSessionArguments) Descriptor() ([]byte, []int) { + return file_controller_api_resources_aliases_v1_alias_proto_rawDescGZIP(), []int{2} +} + +func (x *AuthorizeSessionArguments) GetHostId() string { + if x != nil { + return x.HostId + } + return "" +} + +var File_controller_api_resources_aliases_v1_alias_proto protoreflect.FileDescriptor + +var file_controller_api_resources_aliases_v1_alias_proto_rawDesc = []byte{ + 0x0a, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, + 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x23, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x6c, 0x69, 0x61, + 0x73, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x1a, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 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, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, + 0x69, 0x73, 0x69, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xf8, + 0x06, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, + 0x65, 0x5f, 0x69, 0x64, 0x18, 0x14, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x63, 0x6f, 0x70, + 0x65, 0x5f, 0x69, 0x64, 0x12, 0x43, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x1e, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, + 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x6e, + 0x66, 0x6f, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x46, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x14, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x0c, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x62, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x42, 0x22, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x1a, 0x0a, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0b, 0x44, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x46, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x50, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x5a, 0x20, 0x01, 0x28, 0x09, 0x42, 0x16, + 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x0e, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x05, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x6d, 0x0a, + 0x0e, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, + 0x64, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x42, 0x27, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x1f, 0x0a, 0x0e, 0x64, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x0d, 0x44, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x52, 0x0e, 0x64, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x12, 0x4a, 0x0a, 0x0a, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x6e, 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, 0x0f, 0xa0, 0xda, 0x29, 0x01, 0x9a, + 0xe3, 0x29, 0x07, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x74, + 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x12, 0x94, 0x01, 0x0a, 0x17, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x5f, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x65, 0x73, 0x18, 0x65, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x41, 0x74, 0x74, 0x72, + 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x42, 0x1e, 0xa0, 0xda, 0x29, 0x01, 0x9a, 0xe3, 0x29, 0x06, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0xfa, 0xd2, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x49, 0x4e, + 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x48, 0x00, 0x52, 0x15, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, + 0x41, 0x6c, 0x69, 0x61, 0x73, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 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, + 0x42, 0x07, 0x0a, 0x05, 0x61, 0x74, 0x74, 0x72, 0x73, 0x22, 0x9a, 0x01, 0x0a, 0x15, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, + 0x74, 0x65, 0x73, 0x12, 0x80, 0x01, 0x0a, 0x1b, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, + 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2e, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x1b, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, 0x67, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x7a, 0x0a, 0x19, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x41, 0x72, 0x67, 0x75, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x12, 0x5d, 0x0a, 0x07, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x64, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x40, 0xa0, 0xda, 0x29, 0x01, 0xc2, 0xdd, 0x29, 0x38, 0x0a, 0x2e, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, + 0x72, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x61, 0x72, 0x67, + 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x64, 0x12, 0x06, + 0x48, 0x6f, 0x73, 0x74, 0x49, 0x64, 0x52, 0x0a, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x42, 0x50, 0x5a, 0x4e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x62, 0x6f, 0x75, 0x6e, 0x64, + 0x61, 0x72, 0x79, 0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x62, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x2f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x3b, 0x61, 0x6c, 0x69, + 0x61, 0x73, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_controller_api_resources_aliases_v1_alias_proto_rawDescOnce sync.Once + file_controller_api_resources_aliases_v1_alias_proto_rawDescData = file_controller_api_resources_aliases_v1_alias_proto_rawDesc +) + +func file_controller_api_resources_aliases_v1_alias_proto_rawDescGZIP() []byte { + file_controller_api_resources_aliases_v1_alias_proto_rawDescOnce.Do(func() { + file_controller_api_resources_aliases_v1_alias_proto_rawDescData = protoimpl.X.CompressGZIP(file_controller_api_resources_aliases_v1_alias_proto_rawDescData) + }) + return file_controller_api_resources_aliases_v1_alias_proto_rawDescData +} + +var file_controller_api_resources_aliases_v1_alias_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_controller_api_resources_aliases_v1_alias_proto_goTypes = []interface{}{ + (*Alias)(nil), // 0: controller.api.resources.aliases.v1.Alias + (*TargetAliasAttributes)(nil), // 1: controller.api.resources.aliases.v1.TargetAliasAttributes + (*AuthorizeSessionArguments)(nil), // 2: controller.api.resources.aliases.v1.AuthorizeSessionArguments + (*scopes.ScopeInfo)(nil), // 3: controller.api.resources.scopes.v1.ScopeInfo + (*wrapperspb.StringValue)(nil), // 4: google.protobuf.StringValue + (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp + (*structpb.Struct)(nil), // 6: google.protobuf.Struct +} +var file_controller_api_resources_aliases_v1_alias_proto_depIdxs = []int32{ + 3, // 0: controller.api.resources.aliases.v1.Alias.scope:type_name -> controller.api.resources.scopes.v1.ScopeInfo + 4, // 1: controller.api.resources.aliases.v1.Alias.name:type_name -> google.protobuf.StringValue + 4, // 2: controller.api.resources.aliases.v1.Alias.description:type_name -> google.protobuf.StringValue + 5, // 3: controller.api.resources.aliases.v1.Alias.created_time:type_name -> google.protobuf.Timestamp + 5, // 4: controller.api.resources.aliases.v1.Alias.updated_time:type_name -> google.protobuf.Timestamp + 4, // 5: controller.api.resources.aliases.v1.Alias.destination_id:type_name -> google.protobuf.StringValue + 6, // 6: controller.api.resources.aliases.v1.Alias.attributes:type_name -> google.protobuf.Struct + 1, // 7: controller.api.resources.aliases.v1.Alias.target_alias_attributes:type_name -> controller.api.resources.aliases.v1.TargetAliasAttributes + 2, // 8: controller.api.resources.aliases.v1.TargetAliasAttributes.authorize_session_arguments:type_name -> controller.api.resources.aliases.v1.AuthorizeSessionArguments + 9, // [9:9] is the sub-list for method output_type + 9, // [9:9] is the sub-list for method input_type + 9, // [9:9] is the sub-list for extension type_name + 9, // [9:9] is the sub-list for extension extendee + 0, // [0:9] is the sub-list for field type_name +} + +func init() { file_controller_api_resources_aliases_v1_alias_proto_init() } +func file_controller_api_resources_aliases_v1_alias_proto_init() { + if File_controller_api_resources_aliases_v1_alias_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_controller_api_resources_aliases_v1_alias_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Alias); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_resources_aliases_v1_alias_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TargetAliasAttributes); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_controller_api_resources_aliases_v1_alias_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AuthorizeSessionArguments); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_controller_api_resources_aliases_v1_alias_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*Alias_Attributes)(nil), + (*Alias_TargetAliasAttributes)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_controller_api_resources_aliases_v1_alias_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_controller_api_resources_aliases_v1_alias_proto_goTypes, + DependencyIndexes: file_controller_api_resources_aliases_v1_alias_proto_depIdxs, + MessageInfos: file_controller_api_resources_aliases_v1_alias_proto_msgTypes, + }.Build() + File_controller_api_resources_aliases_v1_alias_proto = out.File + file_controller_api_resources_aliases_v1_alias_proto_rawDesc = nil + file_controller_api_resources_aliases_v1_alias_proto_goTypes = nil + file_controller_api_resources_aliases_v1_alias_proto_depIdxs = nil +}