From 36f46494111f6d16d103fb208d49616576dbf91e Mon Sep 17 00:00:00 2001 From: Noah Dietz Date: Tue, 3 Aug 2021 14:16:18 -0700 Subject: [PATCH] feat(compute)!: add pagination and an Operation wrapper (#4542) This PR does multiple things due to the breaking nature of the code changes for compute. Breaking changes: paginated APIs now return Iterators long running APIs now return a wrapped Operation type instead of the protobuf-go generated type directly Integration tests are added for all of the new changes. The gapic generator is updated with the aforementioned changes. To enable these changes, genbot will now supply the diregapic flag to the gapic generator based on if the API is generated via googleapis-discovery. --- compute/apiv1/accelerator_types_client.go | 371 ++++-- .../accelerator_types_client_example_test.go | 33 +- compute/apiv1/addresses_client.go | 395 ++++-- .../apiv1/addresses_client_example_test.go | 33 +- compute/apiv1/autoscalers_client.go | 437 +++++-- .../apiv1/autoscalers_client_example_test.go | 33 +- compute/apiv1/backend_buckets_client.go | 258 ++-- .../backend_buckets_client_example_test.go | 17 +- compute/apiv1/backend_services_client.go | 473 ++++--- .../backend_services_client_example_test.go | 33 +- compute/apiv1/disk_types_client.go | 361 ++++-- .../apiv1/disk_types_client_example_test.go | 33 +- compute/apiv1/disks_client.go | 473 ++++--- compute/apiv1/disks_client_example_test.go | 33 +- compute/apiv1/external_vpn_gateways_client.go | 222 +++- ...ternal_vpn_gateways_client_example_test.go | 17 +- compute/apiv1/firewall_policies_client.go | 312 +++-- .../firewall_policies_client_example_test.go | 17 +- compute/apiv1/firewalls_client.go | 234 ++-- .../apiv1/firewalls_client_example_test.go | 17 +- compute/apiv1/forwarding_rules_client.go | 449 +++++-- .../forwarding_rules_client_example_test.go | 33 +- compute/apiv1/global_addresses_client.go | 155 ++- .../global_addresses_client_example_test.go | 17 +- .../apiv1/global_forwarding_rules_client.go | 199 +-- ...al_forwarding_rules_client_example_test.go | 17 +- .../global_network_endpoint_groups_client.go | 397 ++++-- ...ork_endpoint_groups_client_example_test.go | 33 +- compute/apiv1/global_operations_client.go | 413 ++++-- .../global_operations_client_example_test.go | 33 +- .../global_organization_operations_client.go | 149 ++- ...nization_operations_client_example_test.go | 17 +- ...global_public_delegated_prefixes_client.go | 222 +++- ..._delegated_prefixes_client_example_test.go | 17 +- compute/apiv1/health_checks_client.go | 437 +++++-- .../health_checks_client_example_test.go | 33 +- compute/apiv1/images_client.go | 246 ++-- compute/apiv1/images_client_example_test.go | 17 +- .../apiv1/instance_group_managers_client.go | 1106 ++++++++++++----- ...ance_group_managers_client_example_test.go | 81 +- compute/apiv1/instance_groups_client.go | 645 +++++++--- .../instance_groups_client_example_test.go | 49 +- compute/apiv1/instance_templates_client.go | 210 +++- .../instance_templates_client_example_test.go | 17 +- compute/apiv1/instances_client.go | 932 +++++++++----- .../apiv1/instances_client_example_test.go | 49 +- .../apiv1/interconnect_attachments_client.go | 425 +++++-- ...connect_attachments_client_example_test.go | 33 +- .../apiv1/interconnect_locations_client.go | 168 ++- ...erconnect_locations_client_example_test.go | 17 +- compute/apiv1/interconnects_client.go | 222 +++- .../interconnects_client_example_test.go | 17 +- compute/apiv1/licenses_client.go | 210 +++- compute/apiv1/licenses_client_example_test.go | 17 +- compute/apiv1/machine_types_client.go | 361 ++++-- .../machine_types_client_example_test.go | 33 +- .../apiv1/network_endpoint_groups_client.go | 539 +++++--- ...ork_endpoint_groups_client_example_test.go | 49 +- compute/apiv1/networks_client.go | 471 ++++--- compute/apiv1/networks_client_example_test.go | 33 +- compute/apiv1/node_groups_client.go | 644 +++++++--- .../apiv1/node_groups_client_example_test.go | 49 +- compute/apiv1/node_templates_client.go | 413 ++++-- .../node_templates_client_example_test.go | 33 +- compute/apiv1/node_types_client.go | 361 ++++-- .../apiv1/node_types_client_example_test.go | 33 +- compute/apiv1/packet_mirrorings_client.go | 425 +++++-- .../packet_mirrorings_client_example_test.go | 33 +- compute/apiv1/projects_client.go | 490 +++++--- compute/apiv1/projects_client_example_test.go | 33 +- .../public_advertised_prefixes_client.go | 222 +++- ...advertised_prefixes_client_example_test.go | 17 +- .../apiv1/public_delegated_prefixes_client.go | 378 ++++-- ..._delegated_prefixes_client_example_test.go | 33 +- compute/apiv1/region_autoscalers_client.go | 187 +-- .../region_autoscalers_client_example_test.go | 17 +- .../apiv1/region_backend_services_client.go | 187 +-- ...on_backend_services_client_example_test.go | 17 +- compute/apiv1/region_commitments_client.go | 383 ++++-- .../region_commitments_client_example_test.go | 33 +- compute/apiv1/region_disk_types_client.go | 131 +- .../region_disk_types_client_example_test.go | 17 +- compute/apiv1/region_disks_client.go | 223 ++-- .../apiv1/region_disks_client_example_test.go | 17 +- .../region_health_check_services_client.go | 222 +++- ...alth_check_services_client_example_test.go | 17 +- compute/apiv1/region_health_checks_client.go | 187 +-- ...egion_health_checks_client_example_test.go | 17 +- .../region_instance_group_managers_client.go | 715 +++++++---- ...ance_group_managers_client_example_test.go | 65 +- .../apiv1/region_instance_groups_client.go | 300 +++-- ...ion_instance_groups_client_example_test.go | 33 +- compute/apiv1/region_instances_client.go | 12 +- .../region_network_endpoint_groups_client.go | 155 ++- ...ork_endpoint_groups_client_example_test.go | 17 +- .../region_notification_endpoints_client.go | 192 ++- ...ification_endpoints_client_example_test.go | 17 +- compute/apiv1/region_operations_client.go | 155 ++- .../region_operations_client_example_test.go | 17 +- .../apiv1/region_ssl_certificates_client.go | 192 ++- ...on_ssl_certificates_client_example_test.go | 17 +- .../region_target_http_proxies_client.go | 222 +++- ...target_http_proxies_client_example_test.go | 17 +- .../region_target_https_proxies_client.go | 234 ++-- ...arget_https_proxies_client_example_test.go | 17 +- compute/apiv1/region_url_maps_client.go | 234 ++-- .../region_url_maps_client_example_test.go | 17 +- compute/apiv1/regions_client.go | 168 ++- compute/apiv1/regions_client_example_test.go | 17 +- compute/apiv1/reservations_client.go | 425 +++++-- .../apiv1/reservations_client_example_test.go | 33 +- compute/apiv1/resource_policies_client.go | 413 ++++-- .../resource_policies_client_example_test.go | 33 +- compute/apiv1/routers_client.go | 620 ++++++--- compute/apiv1/routers_client_example_test.go | 49 +- compute/apiv1/routes_client.go | 192 ++- compute/apiv1/routes_client_example_test.go | 17 +- compute/apiv1/security_policies_client.go | 258 ++-- .../security_policies_client_example_test.go | 17 +- compute/apiv1/smoke_test.go | 153 ++- compute/apiv1/snapshots_client.go | 210 +++- .../apiv1/snapshots_client_example_test.go | 17 +- compute/apiv1/ssl_certificates_client.go | 354 ++++-- .../ssl_certificates_client_example_test.go | 33 +- compute/apiv1/ssl_policies_client.go | 222 +++- .../apiv1/ssl_policies_client_example_test.go | 17 +- compute/apiv1/subnetworks_client.go | 632 +++++++--- .../apiv1/subnetworks_client_example_test.go | 49 +- compute/apiv1/target_grpc_proxies_client.go | 222 +++- ...target_grpc_proxies_client_example_test.go | 17 +- compute/apiv1/target_http_proxies_client.go | 390 ++++-- ...target_http_proxies_client_example_test.go | 33 +- compute/apiv1/target_https_proxies_client.go | 426 ++++--- ...arget_https_proxies_client_example_test.go | 33 +- compute/apiv1/target_instances_client.go | 395 ++++-- .../target_instances_client_example_test.go | 33 +- compute/apiv1/target_pools_client.go | 473 ++++--- .../apiv1/target_pools_client_example_test.go | 33 +- compute/apiv1/target_ssl_proxies_client.go | 258 ++-- .../target_ssl_proxies_client_example_test.go | 17 +- compute/apiv1/target_tcp_proxies_client.go | 234 ++-- .../target_tcp_proxies_client_example_test.go | 17 +- compute/apiv1/target_vpn_gateways_client.go | 395 ++++-- ...target_vpn_gateways_client_example_test.go | 33 +- compute/apiv1/url_maps_client.go | 402 ++++-- compute/apiv1/url_maps_client_example_test.go | 33 +- compute/apiv1/vpn_gateways_client.go | 425 +++++-- .../apiv1/vpn_gateways_client_example_test.go | 33 +- compute/apiv1/vpn_tunnels_client.go | 395 ++++-- .../apiv1/vpn_tunnels_client_example_test.go | 33 +- compute/apiv1/zone_operations_client.go | 155 ++- .../zone_operations_client_example_test.go | 17 +- compute/apiv1/zones_client.go | 168 ++- compute/apiv1/zones_client_example_test.go | 17 +- internal/gapicgen/cmd/genbot/Dockerfile | 2 +- internal/gapicgen/generator/gapics.go | 3 + 156 files changed, 19831 insertions(+), 8607 deletions(-) diff --git a/compute/apiv1/accelerator_types_client.go b/compute/apiv1/accelerator_types_client.go index 419665c9325..b00b366b7ca 100644 --- a/compute/apiv1/accelerator_types_client.go +++ b/compute/apiv1/accelerator_types_client.go @@ -20,10 +20,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newAcceleratorTypesClientHook clientHook @@ -47,9 +51,9 @@ type internalAcceleratorTypesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListAcceleratorTypesRequest, ...gax.CallOption) (*computepb.AcceleratorTypeAggregatedList, error) + AggregatedList(context.Context, *computepb.AggregatedListAcceleratorTypesRequest, ...gax.CallOption) *AcceleratorTypesScopedListPairIterator Get(context.Context, *computepb.GetAcceleratorTypeRequest, ...gax.CallOption) (*computepb.AcceleratorType, error) - List(context.Context, *computepb.ListAcceleratorTypesRequest, ...gax.CallOption) (*computepb.AcceleratorTypeList, error) + List(context.Context, *computepb.ListAcceleratorTypesRequest, ...gax.CallOption) *AcceleratorTypeIterator } // AcceleratorTypesClient is a client for interacting with Google Compute Engine API. @@ -89,7 +93,7 @@ func (c *AcceleratorTypesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of accelerator types. -func (c *AcceleratorTypesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAcceleratorTypesRequest, opts ...gax.CallOption) (*computepb.AcceleratorTypeAggregatedList, error) { +func (c *AcceleratorTypesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAcceleratorTypesRequest, opts ...gax.CallOption) *AcceleratorTypesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } @@ -99,7 +103,7 @@ func (c *AcceleratorTypesClient) Get(ctx context.Context, req *computepb.GetAcce } // List retrieves a list of accelerator types that are available to the specified project. -func (c *AcceleratorTypesClient) List(ctx context.Context, req *computepb.ListAcceleratorTypesRequest, opts ...gax.CallOption) (*computepb.AcceleratorTypeList, error) { +func (c *AcceleratorTypesClient) List(ctx context.Context, req *computepb.ListAcceleratorTypesRequest, opts ...gax.CallOption) *AcceleratorTypeIterator { return c.internalClient.List(ctx, req, opts...) } @@ -170,62 +174,97 @@ func (c *acceleratorTypesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of accelerator types. -func (c *acceleratorTypesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAcceleratorTypesRequest, opts ...gax.CallOption) (*computepb.AcceleratorTypeAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/acceleratorTypes", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err +func (c *acceleratorTypesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAcceleratorTypesRequest, opts ...gax.CallOption) *AcceleratorTypesScopedListPairIterator { + it := &AcceleratorTypesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListAcceleratorTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]AcceleratorTypesScopedListPair, string, error) { + resp := &computepb.AcceleratorTypeAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/acceleratorTypes", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]AcceleratorTypesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, AcceleratorTypesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil } - defer httpRsp.Body.Close() - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.AcceleratorTypeAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + return it } // Get returns the specified accelerator type. @@ -266,57 +305,195 @@ func (c *acceleratorTypesRESTClient) Get(ctx context.Context, req *computepb.Get } // List retrieves a list of accelerator types that are available to the specified project. -func (c *acceleratorTypesRESTClient) List(ctx context.Context, req *computepb.ListAcceleratorTypesRequest, opts ...gax.CallOption) (*computepb.AcceleratorTypeList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/acceleratorTypes", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *acceleratorTypesRESTClient) List(ctx context.Context, req *computepb.ListAcceleratorTypesRequest, opts ...gax.CallOption) *AcceleratorTypeIterator { + it := &AcceleratorTypeIterator{} + req = proto.Clone(req).(*computepb.ListAcceleratorTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.AcceleratorType, string, error) { + resp := &computepb.AcceleratorTypeList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/acceleratorTypes", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// AcceleratorTypeIterator manages a stream of *computepb.AcceleratorType. +type AcceleratorTypeIterator struct { + items []*computepb.AcceleratorType + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.AcceleratorType, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *AcceleratorTypeIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *AcceleratorTypeIterator) Next() (*computepb.AcceleratorType, error) { + var item *computepb.AcceleratorType + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +func (it *AcceleratorTypeIterator) bufLen() int { + return len(it.items) +} + +func (it *AcceleratorTypeIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// AcceleratorTypesScopedListPair is a holder type for string/*computepb.AcceleratorTypesScopedList map entries +type AcceleratorTypesScopedListPair struct { + Key string + Value *computepb.AcceleratorTypesScopedList +} + +// AcceleratorTypesScopedListPairIterator manages a stream of AcceleratorTypesScopedListPair. +type AcceleratorTypesScopedListPairIterator struct { + items []AcceleratorTypesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []AcceleratorTypesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *AcceleratorTypesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *AcceleratorTypesScopedListPairIterator) Next() (AcceleratorTypesScopedListPair, error) { + var item AcceleratorTypesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.AcceleratorTypeList{} +func (it *AcceleratorTypesScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *AcceleratorTypesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// Operation represents a long running operation for this API. +type Operation struct { + proto *computepb.Operation +} + +// Proto returns the raw type this wraps. +func (o *Operation) Proto() *computepb.Operation { + return o.proto } diff --git a/compute/apiv1/accelerator_types_client_example_test.go b/compute/apiv1/accelerator_types_client_example_test.go index ddb62c81c7c..a8d17807d91 100644 --- a/compute/apiv1/accelerator_types_client_example_test.go +++ b/compute/apiv1/accelerator_types_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleAcceleratorTypesClient_AggregatedList() { req := &computepb.AggregatedListAcceleratorTypesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleAcceleratorTypesClient_Get() { @@ -84,10 +91,16 @@ func ExampleAcceleratorTypesClient_List() { req := &computepb.ListAcceleratorTypesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/addresses_client.go b/compute/apiv1/addresses_client.go index 6764aff272d..88e80aa565f 100644 --- a/compute/apiv1/addresses_client.go +++ b/compute/apiv1/addresses_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newAddressesClientHook clientHook @@ -50,11 +54,11 @@ type internalAddressesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListAddressesRequest, ...gax.CallOption) (*computepb.AddressAggregatedList, error) - Delete(context.Context, *computepb.DeleteAddressRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListAddressesRequest, ...gax.CallOption) *AddressesScopedListPairIterator + Delete(context.Context, *computepb.DeleteAddressRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetAddressRequest, ...gax.CallOption) (*computepb.Address, error) - Insert(context.Context, *computepb.InsertAddressRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListAddressesRequest, ...gax.CallOption) (*computepb.AddressList, error) + Insert(context.Context, *computepb.InsertAddressRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListAddressesRequest, ...gax.CallOption) *AddressIterator } // AddressesClient is a client for interacting with Google Compute Engine API. @@ -92,12 +96,12 @@ func (c *AddressesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of addresses. -func (c *AddressesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAddressesRequest, opts ...gax.CallOption) (*computepb.AddressAggregatedList, error) { +func (c *AddressesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAddressesRequest, opts ...gax.CallOption) *AddressesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified address resource. -func (c *AddressesClient) Delete(ctx context.Context, req *computepb.DeleteAddressRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *AddressesClient) Delete(ctx context.Context, req *computepb.DeleteAddressRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -107,12 +111,12 @@ func (c *AddressesClient) Get(ctx context.Context, req *computepb.GetAddressRequ } // Insert creates an address resource in the specified project by using the data included in the request. -func (c *AddressesClient) Insert(ctx context.Context, req *computepb.InsertAddressRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *AddressesClient) Insert(ctx context.Context, req *computepb.InsertAddressRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of addresses contained within the specified region. -func (c *AddressesClient) List(ctx context.Context, req *computepb.ListAddressesRequest, opts ...gax.CallOption) (*computepb.AddressList, error) { +func (c *AddressesClient) List(ctx context.Context, req *computepb.ListAddressesRequest, opts ...gax.CallOption) *AddressIterator { return c.internalClient.List(ctx, req, opts...) } @@ -181,66 +185,101 @@ func (c *addressesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of addresses. -func (c *addressesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAddressesRequest, opts ...gax.CallOption) (*computepb.AddressAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/addresses", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *addressesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAddressesRequest, opts ...gax.CallOption) *AddressesScopedListPairIterator { + it := &AddressesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListAddressesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.AddressAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]AddressesScopedListPair, string, error) { + resp := &computepb.AddressAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/addresses", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]AddressesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, AddressesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified address resource. -func (c *addressesRESTClient) Delete(ctx context.Context, req *computepb.DeleteAddressRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *addressesRESTClient) Delete(ctx context.Context, req *computepb.DeleteAddressRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/addresses/%v", req.GetProject(), req.GetRegion(), req.GetAddress()) @@ -280,7 +319,11 @@ func (c *addressesRESTClient) Delete(ctx context.Context, req *computepb.DeleteA unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified address resource. @@ -321,7 +364,7 @@ func (c *addressesRESTClient) Get(ctx context.Context, req *computepb.GetAddress } // Insert creates an address resource in the specified project by using the data included in the request. -func (c *addressesRESTClient) Insert(ctx context.Context, req *computepb.InsertAddressRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *addressesRESTClient) Insert(ctx context.Context, req *computepb.InsertAddressRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAddressResource() jsonReq, err := m.Marshal(body) @@ -368,61 +411,193 @@ func (c *addressesRESTClient) Insert(ctx context.Context, req *computepb.InsertA unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List retrieves a list of addresses contained within the specified region. -func (c *addressesRESTClient) List(ctx context.Context, req *computepb.ListAddressesRequest, opts ...gax.CallOption) (*computepb.AddressList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/addresses", req.GetProject(), req.GetRegion()) +func (c *addressesRESTClient) List(ctx context.Context, req *computepb.ListAddressesRequest, opts ...gax.CallOption) *AddressIterator { + it := &AddressIterator{} + req = proto.Clone(req).(*computepb.ListAddressesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Address, string, error) { + resp := &computepb.AddressList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/addresses", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it +} - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } +// AddressIterator manages a stream of *computepb.Address. +type AddressIterator struct { + items []*computepb.Address + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Address, nextPageToken string, err error) +} - baseUrl.RawQuery = params.Encode() +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *AddressIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *AddressIterator) Next() (*computepb.Address, error) { + var item *computepb.Address + if err := it.nextFunc(); err != nil { + return item, err } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +func (it *AddressIterator) bufLen() int { + return len(it.items) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +func (it *AddressIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// AddressesScopedListPair is a holder type for string/*computepb.AddressesScopedList map entries +type AddressesScopedListPair struct { + Key string + Value *computepb.AddressesScopedList +} + +// AddressesScopedListPairIterator manages a stream of AddressesScopedListPair. +type AddressesScopedListPairIterator struct { + items []AddressesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []AddressesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *AddressesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *AddressesScopedListPairIterator) Next() (AddressesScopedListPair, error) { + var item AddressesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.AddressList{} +func (it *AddressesScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *AddressesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/addresses_client_example_test.go b/compute/apiv1/addresses_client_example_test.go index 8349df07d7b..641691dae46 100644 --- a/compute/apiv1/addresses_client_example_test.go +++ b/compute/apiv1/addresses_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleAddressesClient_AggregatedList() { req := &computepb.AggregatedListAddressesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleAddressesClient_Delete() { @@ -122,10 +129,16 @@ func ExampleAddressesClient_List() { req := &computepb.ListAddressesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/autoscalers_client.go b/compute/apiv1/autoscalers_client.go index a95f43254b2..e3903d2669d 100644 --- a/compute/apiv1/autoscalers_client.go +++ b/compute/apiv1/autoscalers_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newAutoscalersClientHook clientHook @@ -52,13 +56,13 @@ type internalAutoscalersClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListAutoscalersRequest, ...gax.CallOption) (*computepb.AutoscalerAggregatedList, error) - Delete(context.Context, *computepb.DeleteAutoscalerRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListAutoscalersRequest, ...gax.CallOption) *AutoscalersScopedListPairIterator + Delete(context.Context, *computepb.DeleteAutoscalerRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetAutoscalerRequest, ...gax.CallOption) (*computepb.Autoscaler, error) - Insert(context.Context, *computepb.InsertAutoscalerRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListAutoscalersRequest, ...gax.CallOption) (*computepb.AutoscalerList, error) - Patch(context.Context, *computepb.PatchAutoscalerRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateAutoscalerRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertAutoscalerRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListAutoscalersRequest, ...gax.CallOption) *AutoscalerIterator + Patch(context.Context, *computepb.PatchAutoscalerRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateAutoscalerRequest, ...gax.CallOption) (*Operation, error) } // AutoscalersClient is a client for interacting with Google Compute Engine API. @@ -96,12 +100,12 @@ func (c *AutoscalersClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of autoscalers. -func (c *AutoscalersClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAutoscalersRequest, opts ...gax.CallOption) (*computepb.AutoscalerAggregatedList, error) { +func (c *AutoscalersClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAutoscalersRequest, opts ...gax.CallOption) *AutoscalersScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified autoscaler. -func (c *AutoscalersClient) Delete(ctx context.Context, req *computepb.DeleteAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *AutoscalersClient) Delete(ctx context.Context, req *computepb.DeleteAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -111,22 +115,22 @@ func (c *AutoscalersClient) Get(ctx context.Context, req *computepb.GetAutoscale } // Insert creates an autoscaler in the specified project using the data included in the request. -func (c *AutoscalersClient) Insert(ctx context.Context, req *computepb.InsertAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *AutoscalersClient) Insert(ctx context.Context, req *computepb.InsertAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of autoscalers contained within the specified zone. -func (c *AutoscalersClient) List(ctx context.Context, req *computepb.ListAutoscalersRequest, opts ...gax.CallOption) (*computepb.AutoscalerList, error) { +func (c *AutoscalersClient) List(ctx context.Context, req *computepb.ListAutoscalersRequest, opts ...gax.CallOption) *AutoscalerIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates an autoscaler in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *AutoscalersClient) Patch(ctx context.Context, req *computepb.PatchAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *AutoscalersClient) Patch(ctx context.Context, req *computepb.PatchAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // Update updates an autoscaler in the specified project using the data included in the request. -func (c *AutoscalersClient) Update(ctx context.Context, req *computepb.UpdateAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *AutoscalersClient) Update(ctx context.Context, req *computepb.UpdateAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -195,66 +199,101 @@ func (c *autoscalersRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of autoscalers. -func (c *autoscalersRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAutoscalersRequest, opts ...gax.CallOption) (*computepb.AutoscalerAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/autoscalers", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *autoscalersRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListAutoscalersRequest, opts ...gax.CallOption) *AutoscalersScopedListPairIterator { + it := &AutoscalersScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListAutoscalersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.AutoscalerAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]AutoscalersScopedListPair, string, error) { + resp := &computepb.AutoscalerAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/autoscalers", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]AutoscalersScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, AutoscalersScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified autoscaler. -func (c *autoscalersRESTClient) Delete(ctx context.Context, req *computepb.DeleteAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *autoscalersRESTClient) Delete(ctx context.Context, req *computepb.DeleteAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/autoscalers/%v", req.GetProject(), req.GetZone(), req.GetAutoscaler()) @@ -294,7 +333,11 @@ func (c *autoscalersRESTClient) Delete(ctx context.Context, req *computepb.Delet unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified autoscaler resource. Gets a list of available autoscalers by making a list() request. @@ -335,7 +378,7 @@ func (c *autoscalersRESTClient) Get(ctx context.Context, req *computepb.GetAutos } // Insert creates an autoscaler in the specified project using the data included in the request. -func (c *autoscalersRESTClient) Insert(ctx context.Context, req *computepb.InsertAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *autoscalersRESTClient) Insert(ctx context.Context, req *computepb.InsertAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAutoscalerResource() jsonReq, err := m.Marshal(body) @@ -382,67 +425,99 @@ func (c *autoscalersRESTClient) Insert(ctx context.Context, req *computepb.Inser unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of autoscalers contained within the specified zone. -func (c *autoscalersRESTClient) List(ctx context.Context, req *computepb.ListAutoscalersRequest, opts ...gax.CallOption) (*computepb.AutoscalerList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/autoscalers", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of autoscalers contained within the specified zone. +func (c *autoscalersRESTClient) List(ctx context.Context, req *computepb.ListAutoscalersRequest, opts ...gax.CallOption) *AutoscalerIterator { + it := &AutoscalerIterator{} + req = proto.Clone(req).(*computepb.ListAutoscalersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.AutoscalerList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Autoscaler, string, error) { + resp := &computepb.AutoscalerList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/autoscalers", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates an autoscaler in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *autoscalersRESTClient) Patch(ctx context.Context, req *computepb.PatchAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *autoscalersRESTClient) Patch(ctx context.Context, req *computepb.PatchAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAutoscalerResource() jsonReq, err := m.Marshal(body) @@ -492,11 +567,15 @@ func (c *autoscalersRESTClient) Patch(ctx context.Context, req *computepb.PatchA unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates an autoscaler in the specified project using the data included in the request. -func (c *autoscalersRESTClient) Update(ctx context.Context, req *computepb.UpdateAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *autoscalersRESTClient) Update(ctx context.Context, req *computepb.UpdateAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAutoscalerResource() jsonReq, err := m.Marshal(body) @@ -546,5 +625,109 @@ func (c *autoscalersRESTClient) Update(ctx context.Context, req *computepb.Updat unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// AutoscalerIterator manages a stream of *computepb.Autoscaler. +type AutoscalerIterator struct { + items []*computepb.Autoscaler + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Autoscaler, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *AutoscalerIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *AutoscalerIterator) Next() (*computepb.Autoscaler, error) { + var item *computepb.Autoscaler + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *AutoscalerIterator) bufLen() int { + return len(it.items) +} + +func (it *AutoscalerIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// AutoscalersScopedListPair is a holder type for string/*computepb.AutoscalersScopedList map entries +type AutoscalersScopedListPair struct { + Key string + Value *computepb.AutoscalersScopedList +} + +// AutoscalersScopedListPairIterator manages a stream of AutoscalersScopedListPair. +type AutoscalersScopedListPairIterator struct { + items []AutoscalersScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []AutoscalersScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *AutoscalersScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *AutoscalersScopedListPairIterator) Next() (AutoscalersScopedListPair, error) { + var item AutoscalersScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *AutoscalersScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *AutoscalersScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/autoscalers_client_example_test.go b/compute/apiv1/autoscalers_client_example_test.go index 48fa08ea659..54ccc45c32b 100644 --- a/compute/apiv1/autoscalers_client_example_test.go +++ b/compute/apiv1/autoscalers_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleAutoscalersClient_AggregatedList() { req := &computepb.AggregatedListAutoscalersRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleAutoscalersClient_Delete() { @@ -122,12 +129,18 @@ func ExampleAutoscalersClient_List() { req := &computepb.ListAutoscalersRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleAutoscalersClient_Patch() { diff --git a/compute/apiv1/backend_buckets_client.go b/compute/apiv1/backend_buckets_client.go index 1a355810595..dee9102e1be 100644 --- a/compute/apiv1/backend_buckets_client.go +++ b/compute/apiv1/backend_buckets_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newBackendBucketsClientHook clientHook @@ -53,14 +56,14 @@ type internalBackendBucketsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddSignedUrlKey(context.Context, *computepb.AddSignedUrlKeyBackendBucketRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteBackendBucketRequest, ...gax.CallOption) (*computepb.Operation, error) - DeleteSignedUrlKey(context.Context, *computepb.DeleteSignedUrlKeyBackendBucketRequest, ...gax.CallOption) (*computepb.Operation, error) + AddSignedUrlKey(context.Context, *computepb.AddSignedUrlKeyBackendBucketRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteBackendBucketRequest, ...gax.CallOption) (*Operation, error) + DeleteSignedUrlKey(context.Context, *computepb.DeleteSignedUrlKeyBackendBucketRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetBackendBucketRequest, ...gax.CallOption) (*computepb.BackendBucket, error) - Insert(context.Context, *computepb.InsertBackendBucketRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListBackendBucketsRequest, ...gax.CallOption) (*computepb.BackendBucketList, error) - Patch(context.Context, *computepb.PatchBackendBucketRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateBackendBucketRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertBackendBucketRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListBackendBucketsRequest, ...gax.CallOption) *BackendBucketIterator + Patch(context.Context, *computepb.PatchBackendBucketRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateBackendBucketRequest, ...gax.CallOption) (*Operation, error) } // BackendBucketsClient is a client for interacting with Google Compute Engine API. @@ -98,17 +101,17 @@ func (c *BackendBucketsClient) Connection() *grpc.ClientConn { } // AddSignedUrlKey adds a key for validating requests with signed URLs for this backend bucket. -func (c *BackendBucketsClient) AddSignedUrlKey(ctx context.Context, req *computepb.AddSignedUrlKeyBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendBucketsClient) AddSignedUrlKey(ctx context.Context, req *computepb.AddSignedUrlKeyBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddSignedUrlKey(ctx, req, opts...) } // Delete deletes the specified BackendBucket resource. -func (c *BackendBucketsClient) Delete(ctx context.Context, req *computepb.DeleteBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendBucketsClient) Delete(ctx context.Context, req *computepb.DeleteBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } // DeleteSignedUrlKey deletes a key for validating requests with signed URLs for this backend bucket. -func (c *BackendBucketsClient) DeleteSignedUrlKey(ctx context.Context, req *computepb.DeleteSignedUrlKeyBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendBucketsClient) DeleteSignedUrlKey(ctx context.Context, req *computepb.DeleteSignedUrlKeyBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DeleteSignedUrlKey(ctx, req, opts...) } @@ -118,22 +121,22 @@ func (c *BackendBucketsClient) Get(ctx context.Context, req *computepb.GetBacken } // Insert creates a BackendBucket resource in the specified project using the data included in the request. -func (c *BackendBucketsClient) Insert(ctx context.Context, req *computepb.InsertBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendBucketsClient) Insert(ctx context.Context, req *computepb.InsertBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of BackendBucket resources available to the specified project. -func (c *BackendBucketsClient) List(ctx context.Context, req *computepb.ListBackendBucketsRequest, opts ...gax.CallOption) (*computepb.BackendBucketList, error) { +func (c *BackendBucketsClient) List(ctx context.Context, req *computepb.ListBackendBucketsRequest, opts ...gax.CallOption) *BackendBucketIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates the specified BackendBucket resource with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *BackendBucketsClient) Patch(ctx context.Context, req *computepb.PatchBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendBucketsClient) Patch(ctx context.Context, req *computepb.PatchBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // Update updates the specified BackendBucket resource with the data included in the request. -func (c *BackendBucketsClient) Update(ctx context.Context, req *computepb.UpdateBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendBucketsClient) Update(ctx context.Context, req *computepb.UpdateBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -202,7 +205,7 @@ func (c *backendBucketsRESTClient) Connection() *grpc.ClientConn { } // AddSignedUrlKey adds a key for validating requests with signed URLs for this backend bucket. -func (c *backendBucketsRESTClient) AddSignedUrlKey(ctx context.Context, req *computepb.AddSignedUrlKeyBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendBucketsRESTClient) AddSignedUrlKey(ctx context.Context, req *computepb.AddSignedUrlKeyBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSignedUrlKeyResource() jsonReq, err := m.Marshal(body) @@ -249,11 +252,15 @@ func (c *backendBucketsRESTClient) AddSignedUrlKey(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified BackendBucket resource. -func (c *backendBucketsRESTClient) Delete(ctx context.Context, req *computepb.DeleteBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendBucketsRESTClient) Delete(ctx context.Context, req *computepb.DeleteBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/backendBuckets/%v", req.GetProject(), req.GetBackendBucket()) @@ -293,11 +300,15 @@ func (c *backendBucketsRESTClient) Delete(ctx context.Context, req *computepb.De unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DeleteSignedUrlKey deletes a key for validating requests with signed URLs for this backend bucket. -func (c *backendBucketsRESTClient) DeleteSignedUrlKey(ctx context.Context, req *computepb.DeleteSignedUrlKeyBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendBucketsRESTClient) DeleteSignedUrlKey(ctx context.Context, req *computepb.DeleteSignedUrlKeyBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/backendBuckets/%v/deleteSignedUrlKey", req.GetProject(), req.GetBackendBucket()) @@ -340,7 +351,11 @@ func (c *backendBucketsRESTClient) DeleteSignedUrlKey(ctx context.Context, req * unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified BackendBucket resource. Gets a list of available backend buckets by making a list() request. @@ -381,7 +396,7 @@ func (c *backendBucketsRESTClient) Get(ctx context.Context, req *computepb.GetBa } // Insert creates a BackendBucket resource in the specified project using the data included in the request. -func (c *backendBucketsRESTClient) Insert(ctx context.Context, req *computepb.InsertBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendBucketsRESTClient) Insert(ctx context.Context, req *computepb.InsertBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBackendBucketResource() jsonReq, err := m.Marshal(body) @@ -428,67 +443,99 @@ func (c *backendBucketsRESTClient) Insert(ctx context.Context, req *computepb.In unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of BackendBucket resources available to the specified project. -func (c *backendBucketsRESTClient) List(ctx context.Context, req *computepb.ListBackendBucketsRequest, opts ...gax.CallOption) (*computepb.BackendBucketList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/backendBuckets", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of BackendBucket resources available to the specified project. +func (c *backendBucketsRESTClient) List(ctx context.Context, req *computepb.ListBackendBucketsRequest, opts ...gax.CallOption) *BackendBucketIterator { + it := &BackendBucketIterator{} + req = proto.Clone(req).(*computepb.ListBackendBucketsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.BackendBucketList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.BackendBucket, string, error) { + resp := &computepb.BackendBucketList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/backendBuckets", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates the specified BackendBucket resource with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *backendBucketsRESTClient) Patch(ctx context.Context, req *computepb.PatchBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendBucketsRESTClient) Patch(ctx context.Context, req *computepb.PatchBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBackendBucketResource() jsonReq, err := m.Marshal(body) @@ -535,11 +582,15 @@ func (c *backendBucketsRESTClient) Patch(ctx context.Context, req *computepb.Pat unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates the specified BackendBucket resource with the data included in the request. -func (c *backendBucketsRESTClient) Update(ctx context.Context, req *computepb.UpdateBackendBucketRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendBucketsRESTClient) Update(ctx context.Context, req *computepb.UpdateBackendBucketRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBackendBucketResource() jsonReq, err := m.Marshal(body) @@ -586,5 +637,56 @@ func (c *backendBucketsRESTClient) Update(ctx context.Context, req *computepb.Up unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// BackendBucketIterator manages a stream of *computepb.BackendBucket. +type BackendBucketIterator struct { + items []*computepb.BackendBucket + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.BackendBucket, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *BackendBucketIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *BackendBucketIterator) Next() (*computepb.BackendBucket, error) { + var item *computepb.BackendBucket + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *BackendBucketIterator) bufLen() int { + return len(it.items) +} + +func (it *BackendBucketIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/backend_buckets_client_example_test.go b/compute/apiv1/backend_buckets_client_example_test.go index 1a7f3526506..e672df60f00 100644 --- a/compute/apiv1/backend_buckets_client_example_test.go +++ b/compute/apiv1/backend_buckets_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -141,12 +142,18 @@ func ExampleBackendBucketsClient_List() { req := &computepb.ListBackendBucketsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleBackendBucketsClient_Patch() { diff --git a/compute/apiv1/backend_services_client.go b/compute/apiv1/backend_services_client.go index cce773cd11f..a3b3bb04122 100644 --- a/compute/apiv1/backend_services_client.go +++ b/compute/apiv1/backend_services_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newBackendServicesClientHook clientHook @@ -56,17 +60,17 @@ type internalBackendServicesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddSignedUrlKey(context.Context, *computepb.AddSignedUrlKeyBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) - AggregatedList(context.Context, *computepb.AggregatedListBackendServicesRequest, ...gax.CallOption) (*computepb.BackendServiceAggregatedList, error) - Delete(context.Context, *computepb.DeleteBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) - DeleteSignedUrlKey(context.Context, *computepb.DeleteSignedUrlKeyBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) + AddSignedUrlKey(context.Context, *computepb.AddSignedUrlKeyBackendServiceRequest, ...gax.CallOption) (*Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListBackendServicesRequest, ...gax.CallOption) *BackendServicesScopedListPairIterator + Delete(context.Context, *computepb.DeleteBackendServiceRequest, ...gax.CallOption) (*Operation, error) + DeleteSignedUrlKey(context.Context, *computepb.DeleteSignedUrlKeyBackendServiceRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetBackendServiceRequest, ...gax.CallOption) (*computepb.BackendService, error) GetHealth(context.Context, *computepb.GetHealthBackendServiceRequest, ...gax.CallOption) (*computepb.BackendServiceGroupHealth, error) - Insert(context.Context, *computepb.InsertBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListBackendServicesRequest, ...gax.CallOption) (*computepb.BackendServiceList, error) - Patch(context.Context, *computepb.PatchBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetSecurityPolicy(context.Context, *computepb.SetSecurityPolicyBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertBackendServiceRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListBackendServicesRequest, ...gax.CallOption) *BackendServiceIterator + Patch(context.Context, *computepb.PatchBackendServiceRequest, ...gax.CallOption) (*Operation, error) + SetSecurityPolicy(context.Context, *computepb.SetSecurityPolicyBackendServiceRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateBackendServiceRequest, ...gax.CallOption) (*Operation, error) } // BackendServicesClient is a client for interacting with Google Compute Engine API. @@ -104,22 +108,22 @@ func (c *BackendServicesClient) Connection() *grpc.ClientConn { } // AddSignedUrlKey adds a key for validating requests with signed URLs for this backend service. -func (c *BackendServicesClient) AddSignedUrlKey(ctx context.Context, req *computepb.AddSignedUrlKeyBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendServicesClient) AddSignedUrlKey(ctx context.Context, req *computepb.AddSignedUrlKeyBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddSignedUrlKey(ctx, req, opts...) } // AggregatedList retrieves the list of all BackendService resources, regional and global, available to the specified project. -func (c *BackendServicesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListBackendServicesRequest, opts ...gax.CallOption) (*computepb.BackendServiceAggregatedList, error) { +func (c *BackendServicesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListBackendServicesRequest, opts ...gax.CallOption) *BackendServicesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified BackendService resource. -func (c *BackendServicesClient) Delete(ctx context.Context, req *computepb.DeleteBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendServicesClient) Delete(ctx context.Context, req *computepb.DeleteBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } // DeleteSignedUrlKey deletes a key for validating requests with signed URLs for this backend service. -func (c *BackendServicesClient) DeleteSignedUrlKey(ctx context.Context, req *computepb.DeleteSignedUrlKeyBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendServicesClient) DeleteSignedUrlKey(ctx context.Context, req *computepb.DeleteSignedUrlKeyBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DeleteSignedUrlKey(ctx, req, opts...) } @@ -138,27 +142,27 @@ func (c *BackendServicesClient) GetHealth(ctx context.Context, req *computepb.Ge } // Insert creates a BackendService resource in the specified project using the data included in the request. For more information, see Backend services overview. -func (c *BackendServicesClient) Insert(ctx context.Context, req *computepb.InsertBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendServicesClient) Insert(ctx context.Context, req *computepb.InsertBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of BackendService resources available to the specified project. -func (c *BackendServicesClient) List(ctx context.Context, req *computepb.ListBackendServicesRequest, opts ...gax.CallOption) (*computepb.BackendServiceList, error) { +func (c *BackendServicesClient) List(ctx context.Context, req *computepb.ListBackendServicesRequest, opts ...gax.CallOption) *BackendServiceIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified BackendService resource with the data included in the request. For more information, see Backend services overview. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *BackendServicesClient) Patch(ctx context.Context, req *computepb.PatchBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendServicesClient) Patch(ctx context.Context, req *computepb.PatchBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // SetSecurityPolicy sets the Google Cloud Armor security policy for the specified backend service. For more information, see Google Cloud Armor Overview -func (c *BackendServicesClient) SetSecurityPolicy(ctx context.Context, req *computepb.SetSecurityPolicyBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendServicesClient) SetSecurityPolicy(ctx context.Context, req *computepb.SetSecurityPolicyBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetSecurityPolicy(ctx, req, opts...) } // Update updates the specified BackendService resource with the data included in the request. For more information, see Backend services overview. -func (c *BackendServicesClient) Update(ctx context.Context, req *computepb.UpdateBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *BackendServicesClient) Update(ctx context.Context, req *computepb.UpdateBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -227,7 +231,7 @@ func (c *backendServicesRESTClient) Connection() *grpc.ClientConn { } // AddSignedUrlKey adds a key for validating requests with signed URLs for this backend service. -func (c *backendServicesRESTClient) AddSignedUrlKey(ctx context.Context, req *computepb.AddSignedUrlKeyBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendServicesRESTClient) AddSignedUrlKey(ctx context.Context, req *computepb.AddSignedUrlKeyBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSignedUrlKeyResource() jsonReq, err := m.Marshal(body) @@ -274,70 +278,109 @@ func (c *backendServicesRESTClient) AddSignedUrlKey(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// AggregatedList retrieves the list of all BackendService resources, regional and global, available to the specified project. -func (c *backendServicesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListBackendServicesRequest, opts ...gax.CallOption) (*computepb.BackendServiceAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/backendServices", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// AggregatedList retrieves the list of all BackendService resources, regional and global, available to the specified project. +func (c *backendServicesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListBackendServicesRequest, opts ...gax.CallOption) *BackendServicesScopedListPairIterator { + it := &BackendServicesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListBackendServicesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.BackendServiceAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]BackendServicesScopedListPair, string, error) { + resp := &computepb.BackendServiceAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/backendServices", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]BackendServicesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, BackendServicesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified BackendService resource. -func (c *backendServicesRESTClient) Delete(ctx context.Context, req *computepb.DeleteBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendServicesRESTClient) Delete(ctx context.Context, req *computepb.DeleteBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/backendServices/%v", req.GetProject(), req.GetBackendService()) @@ -377,11 +420,15 @@ func (c *backendServicesRESTClient) Delete(ctx context.Context, req *computepb.D unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DeleteSignedUrlKey deletes a key for validating requests with signed URLs for this backend service. -func (c *backendServicesRESTClient) DeleteSignedUrlKey(ctx context.Context, req *computepb.DeleteSignedUrlKeyBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendServicesRESTClient) DeleteSignedUrlKey(ctx context.Context, req *computepb.DeleteSignedUrlKeyBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/backendServices/%v/deleteSignedUrlKey", req.GetProject(), req.GetBackendService()) @@ -424,7 +471,11 @@ func (c *backendServicesRESTClient) DeleteSignedUrlKey(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified BackendService resource. Gets a list of available backend services. @@ -513,7 +564,7 @@ func (c *backendServicesRESTClient) GetHealth(ctx context.Context, req *computep } // Insert creates a BackendService resource in the specified project using the data included in the request. For more information, see Backend services overview. -func (c *backendServicesRESTClient) Insert(ctx context.Context, req *computepb.InsertBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendServicesRESTClient) Insert(ctx context.Context, req *computepb.InsertBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBackendServiceResource() jsonReq, err := m.Marshal(body) @@ -560,67 +611,99 @@ func (c *backendServicesRESTClient) Insert(ctx context.Context, req *computepb.I unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of BackendService resources available to the specified project. -func (c *backendServicesRESTClient) List(ctx context.Context, req *computepb.ListBackendServicesRequest, opts ...gax.CallOption) (*computepb.BackendServiceList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/backendServices", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of BackendService resources available to the specified project. +func (c *backendServicesRESTClient) List(ctx context.Context, req *computepb.ListBackendServicesRequest, opts ...gax.CallOption) *BackendServiceIterator { + it := &BackendServiceIterator{} + req = proto.Clone(req).(*computepb.ListBackendServicesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.BackendServiceList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.BackendService, string, error) { + resp := &computepb.BackendServiceList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/backendServices", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified BackendService resource with the data included in the request. For more information, see Backend services overview. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *backendServicesRESTClient) Patch(ctx context.Context, req *computepb.PatchBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendServicesRESTClient) Patch(ctx context.Context, req *computepb.PatchBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBackendServiceResource() jsonReq, err := m.Marshal(body) @@ -667,11 +750,15 @@ func (c *backendServicesRESTClient) Patch(ctx context.Context, req *computepb.Pa unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetSecurityPolicy sets the Google Cloud Armor security policy for the specified backend service. For more information, see Google Cloud Armor Overview -func (c *backendServicesRESTClient) SetSecurityPolicy(ctx context.Context, req *computepb.SetSecurityPolicyBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendServicesRESTClient) SetSecurityPolicy(ctx context.Context, req *computepb.SetSecurityPolicyBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSecurityPolicyReferenceResource() jsonReq, err := m.Marshal(body) @@ -718,11 +805,15 @@ func (c *backendServicesRESTClient) SetSecurityPolicy(ctx context.Context, req * unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates the specified BackendService resource with the data included in the request. For more information, see Backend services overview. -func (c *backendServicesRESTClient) Update(ctx context.Context, req *computepb.UpdateBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *backendServicesRESTClient) Update(ctx context.Context, req *computepb.UpdateBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBackendServiceResource() jsonReq, err := m.Marshal(body) @@ -769,5 +860,109 @@ func (c *backendServicesRESTClient) Update(ctx context.Context, req *computepb.U unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// BackendServiceIterator manages a stream of *computepb.BackendService. +type BackendServiceIterator struct { + items []*computepb.BackendService + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.BackendService, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *BackendServiceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *BackendServiceIterator) Next() (*computepb.BackendService, error) { + var item *computepb.BackendService + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *BackendServiceIterator) bufLen() int { + return len(it.items) +} + +func (it *BackendServiceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// BackendServicesScopedListPair is a holder type for string/*computepb.BackendServicesScopedList map entries +type BackendServicesScopedListPair struct { + Key string + Value *computepb.BackendServicesScopedList +} + +// BackendServicesScopedListPairIterator manages a stream of BackendServicesScopedListPair. +type BackendServicesScopedListPairIterator struct { + items []BackendServicesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []BackendServicesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *BackendServicesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *BackendServicesScopedListPairIterator) Next() (BackendServicesScopedListPair, error) { + var item BackendServicesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *BackendServicesScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *BackendServicesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/backend_services_client_example_test.go b/compute/apiv1/backend_services_client_example_test.go index 6bdbd1e68e1..9373a8edd8c 100644 --- a/compute/apiv1/backend_services_client_example_test.go +++ b/compute/apiv1/backend_services_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,12 +66,18 @@ func ExampleBackendServicesClient_AggregatedList() { req := &computepb.AggregatedListBackendServicesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleBackendServicesClient_Delete() { @@ -179,12 +186,18 @@ func ExampleBackendServicesClient_List() { req := &computepb.ListBackendServicesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleBackendServicesClient_Patch() { diff --git a/compute/apiv1/disk_types_client.go b/compute/apiv1/disk_types_client.go index 596153747be..d5e80a46ff1 100644 --- a/compute/apiv1/disk_types_client.go +++ b/compute/apiv1/disk_types_client.go @@ -20,10 +20,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newDiskTypesClientHook clientHook @@ -47,9 +51,9 @@ type internalDiskTypesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListDiskTypesRequest, ...gax.CallOption) (*computepb.DiskTypeAggregatedList, error) + AggregatedList(context.Context, *computepb.AggregatedListDiskTypesRequest, ...gax.CallOption) *DiskTypesScopedListPairIterator Get(context.Context, *computepb.GetDiskTypeRequest, ...gax.CallOption) (*computepb.DiskType, error) - List(context.Context, *computepb.ListDiskTypesRequest, ...gax.CallOption) (*computepb.DiskTypeList, error) + List(context.Context, *computepb.ListDiskTypesRequest, ...gax.CallOption) *DiskTypeIterator } // DiskTypesClient is a client for interacting with Google Compute Engine API. @@ -87,7 +91,7 @@ func (c *DiskTypesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of disk types. -func (c *DiskTypesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListDiskTypesRequest, opts ...gax.CallOption) (*computepb.DiskTypeAggregatedList, error) { +func (c *DiskTypesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListDiskTypesRequest, opts ...gax.CallOption) *DiskTypesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } @@ -97,7 +101,7 @@ func (c *DiskTypesClient) Get(ctx context.Context, req *computepb.GetDiskTypeReq } // List retrieves a list of disk types available to the specified project. -func (c *DiskTypesClient) List(ctx context.Context, req *computepb.ListDiskTypesRequest, opts ...gax.CallOption) (*computepb.DiskTypeList, error) { +func (c *DiskTypesClient) List(ctx context.Context, req *computepb.ListDiskTypesRequest, opts ...gax.CallOption) *DiskTypeIterator { return c.internalClient.List(ctx, req, opts...) } @@ -166,62 +170,97 @@ func (c *diskTypesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of disk types. -func (c *diskTypesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListDiskTypesRequest, opts ...gax.CallOption) (*computepb.DiskTypeAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/diskTypes", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +func (c *diskTypesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListDiskTypesRequest, opts ...gax.CallOption) *DiskTypesScopedListPairIterator { + it := &DiskTypesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListDiskTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]DiskTypesScopedListPair, string, error) { + resp := &computepb.DiskTypeAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/diskTypes", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]DiskTypesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, DiskTypesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.DiskTypeAggregatedList{} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - return rsp, unm.Unmarshal(buf, rsp) + return it } // Get returns the specified disk type. Gets a list of available disk types by making a list() request. @@ -262,57 +301,185 @@ func (c *diskTypesRESTClient) Get(ctx context.Context, req *computepb.GetDiskTyp } // List retrieves a list of disk types available to the specified project. -func (c *diskTypesRESTClient) List(ctx context.Context, req *computepb.ListDiskTypesRequest, opts ...gax.CallOption) (*computepb.DiskTypeList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/diskTypes", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *diskTypesRESTClient) List(ctx context.Context, req *computepb.ListDiskTypesRequest, opts ...gax.CallOption) *DiskTypeIterator { + it := &DiskTypeIterator{} + req = proto.Clone(req).(*computepb.ListDiskTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.DiskType, string, error) { + resp := &computepb.DiskTypeList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/diskTypes", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// DiskTypeIterator manages a stream of *computepb.DiskType. +type DiskTypeIterator struct { + items []*computepb.DiskType + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.DiskType, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DiskTypeIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *DiskTypeIterator) Next() (*computepb.DiskType, error) { + var item *computepb.DiskType + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +func (it *DiskTypeIterator) bufLen() int { + return len(it.items) +} + +func (it *DiskTypeIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// DiskTypesScopedListPair is a holder type for string/*computepb.DiskTypesScopedList map entries +type DiskTypesScopedListPair struct { + Key string + Value *computepb.DiskTypesScopedList +} + +// DiskTypesScopedListPairIterator manages a stream of DiskTypesScopedListPair. +type DiskTypesScopedListPairIterator struct { + items []DiskTypesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []DiskTypesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DiskTypesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *DiskTypesScopedListPairIterator) Next() (DiskTypesScopedListPair, error) { + var item DiskTypesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.DiskTypeList{} +func (it *DiskTypesScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *DiskTypesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/disk_types_client_example_test.go b/compute/apiv1/disk_types_client_example_test.go index db2c18bb93e..138148849b1 100644 --- a/compute/apiv1/disk_types_client_example_test.go +++ b/compute/apiv1/disk_types_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleDiskTypesClient_AggregatedList() { req := &computepb.AggregatedListDiskTypesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleDiskTypesClient_Get() { @@ -84,10 +91,16 @@ func ExampleDiskTypesClient_List() { req := &computepb.ListDiskTypesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/disks_client.go b/compute/apiv1/disks_client.go index d5545baf4ee..40e89bfae31 100644 --- a/compute/apiv1/disks_client.go +++ b/compute/apiv1/disks_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newDisksClientHook clientHook @@ -58,18 +62,18 @@ type internalDisksClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddResourcePolicies(context.Context, *computepb.AddResourcePoliciesDiskRequest, ...gax.CallOption) (*computepb.Operation, error) - AggregatedList(context.Context, *computepb.AggregatedListDisksRequest, ...gax.CallOption) (*computepb.DiskAggregatedList, error) - CreateSnapshot(context.Context, *computepb.CreateSnapshotDiskRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteDiskRequest, ...gax.CallOption) (*computepb.Operation, error) + AddResourcePolicies(context.Context, *computepb.AddResourcePoliciesDiskRequest, ...gax.CallOption) (*Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListDisksRequest, ...gax.CallOption) *DisksScopedListPairIterator + CreateSnapshot(context.Context, *computepb.CreateSnapshotDiskRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteDiskRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetDiskRequest, ...gax.CallOption) (*computepb.Disk, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyDiskRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertDiskRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListDisksRequest, ...gax.CallOption) (*computepb.DiskList, error) - RemoveResourcePolicies(context.Context, *computepb.RemoveResourcePoliciesDiskRequest, ...gax.CallOption) (*computepb.Operation, error) - Resize(context.Context, *computepb.ResizeDiskRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertDiskRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListDisksRequest, ...gax.CallOption) *DiskIterator + RemoveResourcePolicies(context.Context, *computepb.RemoveResourcePoliciesDiskRequest, ...gax.CallOption) (*Operation, error) + Resize(context.Context, *computepb.ResizeDiskRequest, ...gax.CallOption) (*Operation, error) SetIamPolicy(context.Context, *computepb.SetIamPolicyDiskRequest, ...gax.CallOption) (*computepb.Policy, error) - SetLabels(context.Context, *computepb.SetLabelsDiskRequest, ...gax.CallOption) (*computepb.Operation, error) + SetLabels(context.Context, *computepb.SetLabelsDiskRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsDiskRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -108,22 +112,22 @@ func (c *DisksClient) Connection() *grpc.ClientConn { } // AddResourcePolicies adds existing resource policies to a disk. You can only add one policy which will be applied to this disk for scheduling snapshot creation. -func (c *DisksClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *DisksClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddResourcePolicies(ctx, req, opts...) } // AggregatedList retrieves an aggregated list of persistent disks. -func (c *DisksClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListDisksRequest, opts ...gax.CallOption) (*computepb.DiskAggregatedList, error) { +func (c *DisksClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListDisksRequest, opts ...gax.CallOption) *DisksScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // CreateSnapshot creates a snapshot of a specified persistent disk. -func (c *DisksClient) CreateSnapshot(ctx context.Context, req *computepb.CreateSnapshotDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *DisksClient) CreateSnapshot(ctx context.Context, req *computepb.CreateSnapshotDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.CreateSnapshot(ctx, req, opts...) } // Delete deletes the specified persistent disk. Deleting a disk removes its data permanently and is irreversible. However, deleting a disk does not delete any snapshots previously made from the disk. You must separately delete snapshots. -func (c *DisksClient) Delete(ctx context.Context, req *computepb.DeleteDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *DisksClient) Delete(ctx context.Context, req *computepb.DeleteDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -138,22 +142,22 @@ func (c *DisksClient) GetIamPolicy(ctx context.Context, req *computepb.GetIamPol } // Insert creates a persistent disk in the specified project using the data in the request. You can create a disk from a source (sourceImage, sourceSnapshot, or sourceDisk) or create an empty 500 GB data disk by omitting all properties. You can also create a disk that is larger than the default size by specifying the sizeGb property. -func (c *DisksClient) Insert(ctx context.Context, req *computepb.InsertDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *DisksClient) Insert(ctx context.Context, req *computepb.InsertDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of persistent disks contained within the specified zone. -func (c *DisksClient) List(ctx context.Context, req *computepb.ListDisksRequest, opts ...gax.CallOption) (*computepb.DiskList, error) { +func (c *DisksClient) List(ctx context.Context, req *computepb.ListDisksRequest, opts ...gax.CallOption) *DiskIterator { return c.internalClient.List(ctx, req, opts...) } // RemoveResourcePolicies removes resource policies from a disk. -func (c *DisksClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *DisksClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemoveResourcePolicies(ctx, req, opts...) } // Resize resizes the specified persistent disk. You can only increase the size of the disk. -func (c *DisksClient) Resize(ctx context.Context, req *computepb.ResizeDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *DisksClient) Resize(ctx context.Context, req *computepb.ResizeDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Resize(ctx, req, opts...) } @@ -163,7 +167,7 @@ func (c *DisksClient) SetIamPolicy(ctx context.Context, req *computepb.SetIamPol } // SetLabels sets the labels on a disk. To learn more about labels, read the Labeling Resources documentation. -func (c *DisksClient) SetLabels(ctx context.Context, req *computepb.SetLabelsDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *DisksClient) SetLabels(ctx context.Context, req *computepb.SetLabelsDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetLabels(ctx, req, opts...) } @@ -237,7 +241,7 @@ func (c *disksRESTClient) Connection() *grpc.ClientConn { } // AddResourcePolicies adds existing resource policies to a disk. You can only add one policy which will be applied to this disk for scheduling snapshot creation. -func (c *disksRESTClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *disksRESTClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetDisksAddResourcePoliciesRequestResource() jsonReq, err := m.Marshal(body) @@ -284,70 +288,109 @@ func (c *disksRESTClient) AddResourcePolicies(ctx context.Context, req *computep unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// AggregatedList retrieves an aggregated list of persistent disks. -func (c *disksRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListDisksRequest, opts ...gax.CallOption) (*computepb.DiskAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/disks", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// AggregatedList retrieves an aggregated list of persistent disks. +func (c *disksRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListDisksRequest, opts ...gax.CallOption) *DisksScopedListPairIterator { + it := &DisksScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListDisksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.DiskAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]DisksScopedListPair, string, error) { + resp := &computepb.DiskAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/disks", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]DisksScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, DisksScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // CreateSnapshot creates a snapshot of a specified persistent disk. -func (c *disksRESTClient) CreateSnapshot(ctx context.Context, req *computepb.CreateSnapshotDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *disksRESTClient) CreateSnapshot(ctx context.Context, req *computepb.CreateSnapshotDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSnapshotResource() jsonReq, err := m.Marshal(body) @@ -397,11 +440,15 @@ func (c *disksRESTClient) CreateSnapshot(ctx context.Context, req *computepb.Cre unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified persistent disk. Deleting a disk removes its data permanently and is irreversible. However, deleting a disk does not delete any snapshots previously made from the disk. You must separately delete snapshots. -func (c *disksRESTClient) Delete(ctx context.Context, req *computepb.DeleteDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *disksRESTClient) Delete(ctx context.Context, req *computepb.DeleteDiskRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/disks/%v", req.GetProject(), req.GetZone(), req.GetDisk()) @@ -441,7 +488,11 @@ func (c *disksRESTClient) Delete(ctx context.Context, req *computepb.DeleteDiskR unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns a specified persistent disk. Gets a list of available persistent disks by making a list() request. @@ -526,7 +577,7 @@ func (c *disksRESTClient) GetIamPolicy(ctx context.Context, req *computepb.GetIa } // Insert creates a persistent disk in the specified project using the data in the request. You can create a disk from a source (sourceImage, sourceSnapshot, or sourceDisk) or create an empty 500 GB data disk by omitting all properties. You can also create a disk that is larger than the default size by specifying the sizeGb property. -func (c *disksRESTClient) Insert(ctx context.Context, req *computepb.InsertDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *disksRESTClient) Insert(ctx context.Context, req *computepb.InsertDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetDiskResource() jsonReq, err := m.Marshal(body) @@ -576,67 +627,99 @@ func (c *disksRESTClient) Insert(ctx context.Context, req *computepb.InsertDiskR unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of persistent disks contained within the specified zone. -func (c *disksRESTClient) List(ctx context.Context, req *computepb.ListDisksRequest, opts ...gax.CallOption) (*computepb.DiskList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/disks", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of persistent disks contained within the specified zone. +func (c *disksRESTClient) List(ctx context.Context, req *computepb.ListDisksRequest, opts ...gax.CallOption) *DiskIterator { + it := &DiskIterator{} + req = proto.Clone(req).(*computepb.ListDisksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.DiskList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Disk, string, error) { + resp := &computepb.DiskList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/disks", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // RemoveResourcePolicies removes resource policies from a disk. -func (c *disksRESTClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *disksRESTClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetDisksRemoveResourcePoliciesRequestResource() jsonReq, err := m.Marshal(body) @@ -683,11 +766,15 @@ func (c *disksRESTClient) RemoveResourcePolicies(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Resize resizes the specified persistent disk. You can only increase the size of the disk. -func (c *disksRESTClient) Resize(ctx context.Context, req *computepb.ResizeDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *disksRESTClient) Resize(ctx context.Context, req *computepb.ResizeDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetDisksResizeRequestResource() jsonReq, err := m.Marshal(body) @@ -734,7 +821,11 @@ func (c *disksRESTClient) Resize(ctx context.Context, req *computepb.ResizeDiskR unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -782,7 +873,7 @@ func (c *disksRESTClient) SetIamPolicy(ctx context.Context, req *computepb.SetIa } // SetLabels sets the labels on a disk. To learn more about labels, read the Labeling Resources documentation. -func (c *disksRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *disksRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetZoneSetLabelsRequestResource() jsonReq, err := m.Marshal(body) @@ -829,7 +920,11 @@ func (c *disksRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabel unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -875,3 +970,103 @@ func (c *disksRESTClient) TestIamPermissions(ctx context.Context, req *computepb return rsp, unm.Unmarshal(buf, rsp) } + +// DiskIterator manages a stream of *computepb.Disk. +type DiskIterator struct { + items []*computepb.Disk + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Disk, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DiskIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *DiskIterator) Next() (*computepb.Disk, error) { + var item *computepb.Disk + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *DiskIterator) bufLen() int { + return len(it.items) +} + +func (it *DiskIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// DisksScopedListPair is a holder type for string/*computepb.DisksScopedList map entries +type DisksScopedListPair struct { + Key string + Value *computepb.DisksScopedList +} + +// DisksScopedListPairIterator manages a stream of DisksScopedListPair. +type DisksScopedListPairIterator struct { + items []DisksScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []DisksScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *DisksScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *DisksScopedListPairIterator) Next() (DisksScopedListPair, error) { + var item DisksScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *DisksScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *DisksScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/disks_client_example_test.go b/compute/apiv1/disks_client_example_test.go index cbdcd918b75..c4b22d18e27 100644 --- a/compute/apiv1/disks_client_example_test.go +++ b/compute/apiv1/disks_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,12 +66,18 @@ func ExampleDisksClient_AggregatedList() { req := &computepb.AggregatedListDisksRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleDisksClient_CreateSnapshot() { @@ -179,12 +186,18 @@ func ExampleDisksClient_List() { req := &computepb.ListDisksRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleDisksClient_RemoveResourcePolicies() { diff --git a/compute/apiv1/external_vpn_gateways_client.go b/compute/apiv1/external_vpn_gateways_client.go index 26e5de09e62..6b84c088bc2 100644 --- a/compute/apiv1/external_vpn_gateways_client.go +++ b/compute/apiv1/external_vpn_gateways_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newExternalVpnGatewaysClientHook clientHook @@ -51,11 +54,11 @@ type internalExternalVpnGatewaysClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteExternalVpnGatewayRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteExternalVpnGatewayRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetExternalVpnGatewayRequest, ...gax.CallOption) (*computepb.ExternalVpnGateway, error) - Insert(context.Context, *computepb.InsertExternalVpnGatewayRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListExternalVpnGatewaysRequest, ...gax.CallOption) (*computepb.ExternalVpnGatewayList, error) - SetLabels(context.Context, *computepb.SetLabelsExternalVpnGatewayRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertExternalVpnGatewayRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListExternalVpnGatewaysRequest, ...gax.CallOption) *ExternalVpnGatewayIterator + SetLabels(context.Context, *computepb.SetLabelsExternalVpnGatewayRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsExternalVpnGatewayRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -94,7 +97,7 @@ func (c *ExternalVpnGatewaysClient) Connection() *grpc.ClientConn { } // Delete deletes the specified externalVpnGateway. -func (c *ExternalVpnGatewaysClient) Delete(ctx context.Context, req *computepb.DeleteExternalVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ExternalVpnGatewaysClient) Delete(ctx context.Context, req *computepb.DeleteExternalVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -104,17 +107,17 @@ func (c *ExternalVpnGatewaysClient) Get(ctx context.Context, req *computepb.GetE } // Insert creates a ExternalVpnGateway in the specified project using the data included in the request. -func (c *ExternalVpnGatewaysClient) Insert(ctx context.Context, req *computepb.InsertExternalVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ExternalVpnGatewaysClient) Insert(ctx context.Context, req *computepb.InsertExternalVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of ExternalVpnGateway available to the specified project. -func (c *ExternalVpnGatewaysClient) List(ctx context.Context, req *computepb.ListExternalVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.ExternalVpnGatewayList, error) { +func (c *ExternalVpnGatewaysClient) List(ctx context.Context, req *computepb.ListExternalVpnGatewaysRequest, opts ...gax.CallOption) *ExternalVpnGatewayIterator { return c.internalClient.List(ctx, req, opts...) } // SetLabels sets the labels on an ExternalVpnGateway. To learn more about labels, read the Labeling Resources documentation. -func (c *ExternalVpnGatewaysClient) SetLabels(ctx context.Context, req *computepb.SetLabelsExternalVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ExternalVpnGatewaysClient) SetLabels(ctx context.Context, req *computepb.SetLabelsExternalVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetLabels(ctx, req, opts...) } @@ -188,7 +191,7 @@ func (c *externalVpnGatewaysRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified externalVpnGateway. -func (c *externalVpnGatewaysRESTClient) Delete(ctx context.Context, req *computepb.DeleteExternalVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *externalVpnGatewaysRESTClient) Delete(ctx context.Context, req *computepb.DeleteExternalVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/externalVpnGateways/%v", req.GetProject(), req.GetExternalVpnGateway()) @@ -228,7 +231,11 @@ func (c *externalVpnGatewaysRESTClient) Delete(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified externalVpnGateway. Get a list of available externalVpnGateways by making a list() request. @@ -269,7 +276,7 @@ func (c *externalVpnGatewaysRESTClient) Get(ctx context.Context, req *computepb. } // Insert creates a ExternalVpnGateway in the specified project using the data included in the request. -func (c *externalVpnGatewaysRESTClient) Insert(ctx context.Context, req *computepb.InsertExternalVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *externalVpnGatewaysRESTClient) Insert(ctx context.Context, req *computepb.InsertExternalVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetExternalVpnGatewayResource() jsonReq, err := m.Marshal(body) @@ -316,67 +323,99 @@ func (c *externalVpnGatewaysRESTClient) Insert(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of ExternalVpnGateway available to the specified project. -func (c *externalVpnGatewaysRESTClient) List(ctx context.Context, req *computepb.ListExternalVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.ExternalVpnGatewayList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/externalVpnGateways", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of ExternalVpnGateway available to the specified project. +func (c *externalVpnGatewaysRESTClient) List(ctx context.Context, req *computepb.ListExternalVpnGatewaysRequest, opts ...gax.CallOption) *ExternalVpnGatewayIterator { + it := &ExternalVpnGatewayIterator{} + req = proto.Clone(req).(*computepb.ListExternalVpnGatewaysRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ExternalVpnGatewayList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.ExternalVpnGateway, string, error) { + resp := &computepb.ExternalVpnGatewayList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/externalVpnGateways", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetLabels sets the labels on an ExternalVpnGateway. To learn more about labels, read the Labeling Resources documentation. -func (c *externalVpnGatewaysRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsExternalVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *externalVpnGatewaysRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsExternalVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetGlobalSetLabelsRequestResource() jsonReq, err := m.Marshal(body) @@ -416,7 +455,11 @@ func (c *externalVpnGatewaysRESTClient) SetLabels(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -462,3 +505,50 @@ func (c *externalVpnGatewaysRESTClient) TestIamPermissions(ctx context.Context, return rsp, unm.Unmarshal(buf, rsp) } + +// ExternalVpnGatewayIterator manages a stream of *computepb.ExternalVpnGateway. +type ExternalVpnGatewayIterator struct { + items []*computepb.ExternalVpnGateway + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.ExternalVpnGateway, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ExternalVpnGatewayIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ExternalVpnGatewayIterator) Next() (*computepb.ExternalVpnGateway, error) { + var item *computepb.ExternalVpnGateway + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ExternalVpnGatewayIterator) bufLen() int { + return len(it.items) +} + +func (it *ExternalVpnGatewayIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/external_vpn_gateways_client_example_test.go b/compute/apiv1/external_vpn_gateways_client_example_test.go index 820c2c0a3fb..9474f48af26 100644 --- a/compute/apiv1/external_vpn_gateways_client_example_test.go +++ b/compute/apiv1/external_vpn_gateways_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleExternalVpnGatewaysClient_List() { req := &computepb.ListExternalVpnGatewaysRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleExternalVpnGatewaysClient_SetLabels() { diff --git a/compute/apiv1/firewall_policies_client.go b/compute/apiv1/firewall_policies_client.go index 700113b615d..f3c7c07e81a 100644 --- a/compute/apiv1/firewall_policies_client.go +++ b/compute/apiv1/firewall_policies_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newFirewallPoliciesClientHook clientHook @@ -63,22 +66,22 @@ type internalFirewallPoliciesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddAssociation(context.Context, *computepb.AddAssociationFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - AddRule(context.Context, *computepb.AddRuleFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - CloneRules(context.Context, *computepb.CloneRulesFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) + AddAssociation(context.Context, *computepb.AddAssociationFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) + AddRule(context.Context, *computepb.AddRuleFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) + CloneRules(context.Context, *computepb.CloneRulesFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetFirewallPolicyRequest, ...gax.CallOption) (*computepb.FirewallPolicy, error) GetAssociation(context.Context, *computepb.GetAssociationFirewallPolicyRequest, ...gax.CallOption) (*computepb.FirewallPolicyAssociation, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyFirewallPolicyRequest, ...gax.CallOption) (*computepb.Policy, error) GetRule(context.Context, *computepb.GetRuleFirewallPolicyRequest, ...gax.CallOption) (*computepb.FirewallPolicyRule, error) - Insert(context.Context, *computepb.InsertFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListFirewallPoliciesRequest, ...gax.CallOption) (*computepb.FirewallPolicyList, error) + Insert(context.Context, *computepb.InsertFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListFirewallPoliciesRequest, ...gax.CallOption) *FirewallPolicyIterator ListAssociations(context.Context, *computepb.ListAssociationsFirewallPolicyRequest, ...gax.CallOption) (*computepb.FirewallPoliciesListAssociationsResponse, error) - Move(context.Context, *computepb.MoveFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - Patch(context.Context, *computepb.PatchFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - PatchRule(context.Context, *computepb.PatchRuleFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - RemoveAssociation(context.Context, *computepb.RemoveAssociationFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - RemoveRule(context.Context, *computepb.RemoveRuleFirewallPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) + Move(context.Context, *computepb.MoveFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) + Patch(context.Context, *computepb.PatchFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) + PatchRule(context.Context, *computepb.PatchRuleFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) + RemoveAssociation(context.Context, *computepb.RemoveAssociationFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) + RemoveRule(context.Context, *computepb.RemoveRuleFirewallPolicyRequest, ...gax.CallOption) (*Operation, error) SetIamPolicy(context.Context, *computepb.SetIamPolicyFirewallPolicyRequest, ...gax.CallOption) (*computepb.Policy, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsFirewallPolicyRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -118,22 +121,22 @@ func (c *FirewallPoliciesClient) Connection() *grpc.ClientConn { } // AddAssociation inserts an association for the specified firewall policy. -func (c *FirewallPoliciesClient) AddAssociation(ctx context.Context, req *computepb.AddAssociationFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) AddAssociation(ctx context.Context, req *computepb.AddAssociationFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddAssociation(ctx, req, opts...) } // AddRule inserts a rule into a firewall policy. -func (c *FirewallPoliciesClient) AddRule(ctx context.Context, req *computepb.AddRuleFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) AddRule(ctx context.Context, req *computepb.AddRuleFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddRule(ctx, req, opts...) } // CloneRules copies rules to the specified firewall policy. -func (c *FirewallPoliciesClient) CloneRules(ctx context.Context, req *computepb.CloneRulesFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) CloneRules(ctx context.Context, req *computepb.CloneRulesFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.CloneRules(ctx, req, opts...) } // Delete deletes the specified policy. -func (c *FirewallPoliciesClient) Delete(ctx context.Context, req *computepb.DeleteFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) Delete(ctx context.Context, req *computepb.DeleteFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -158,12 +161,12 @@ func (c *FirewallPoliciesClient) GetRule(ctx context.Context, req *computepb.Get } // Insert creates a new policy in the specified project using the data included in the request. -func (c *FirewallPoliciesClient) Insert(ctx context.Context, req *computepb.InsertFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) Insert(ctx context.Context, req *computepb.InsertFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List lists all the policies that have been configured for the specified project. -func (c *FirewallPoliciesClient) List(ctx context.Context, req *computepb.ListFirewallPoliciesRequest, opts ...gax.CallOption) (*computepb.FirewallPolicyList, error) { +func (c *FirewallPoliciesClient) List(ctx context.Context, req *computepb.ListFirewallPoliciesRequest, opts ...gax.CallOption) *FirewallPolicyIterator { return c.internalClient.List(ctx, req, opts...) } @@ -173,27 +176,27 @@ func (c *FirewallPoliciesClient) ListAssociations(ctx context.Context, req *comp } // Move moves the specified firewall policy. -func (c *FirewallPoliciesClient) Move(ctx context.Context, req *computepb.MoveFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) Move(ctx context.Context, req *computepb.MoveFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Move(ctx, req, opts...) } // Patch patches the specified policy with the data included in the request. -func (c *FirewallPoliciesClient) Patch(ctx context.Context, req *computepb.PatchFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) Patch(ctx context.Context, req *computepb.PatchFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // PatchRule patches a rule of the specified priority. -func (c *FirewallPoliciesClient) PatchRule(ctx context.Context, req *computepb.PatchRuleFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) PatchRule(ctx context.Context, req *computepb.PatchRuleFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.PatchRule(ctx, req, opts...) } // RemoveAssociation removes an association for the specified firewall policy. -func (c *FirewallPoliciesClient) RemoveAssociation(ctx context.Context, req *computepb.RemoveAssociationFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) RemoveAssociation(ctx context.Context, req *computepb.RemoveAssociationFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemoveAssociation(ctx, req, opts...) } // RemoveRule deletes a rule of the specified priority. -func (c *FirewallPoliciesClient) RemoveRule(ctx context.Context, req *computepb.RemoveRuleFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallPoliciesClient) RemoveRule(ctx context.Context, req *computepb.RemoveRuleFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemoveRule(ctx, req, opts...) } @@ -272,7 +275,7 @@ func (c *firewallPoliciesRESTClient) Connection() *grpc.ClientConn { } // AddAssociation inserts an association for the specified firewall policy. -func (c *firewallPoliciesRESTClient) AddAssociation(ctx context.Context, req *computepb.AddAssociationFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) AddAssociation(ctx context.Context, req *computepb.AddAssociationFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetFirewallPolicyAssociationResource() jsonReq, err := m.Marshal(body) @@ -322,11 +325,15 @@ func (c *firewallPoliciesRESTClient) AddAssociation(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // AddRule inserts a rule into a firewall policy. -func (c *firewallPoliciesRESTClient) AddRule(ctx context.Context, req *computepb.AddRuleFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) AddRule(ctx context.Context, req *computepb.AddRuleFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetFirewallPolicyRuleResource() jsonReq, err := m.Marshal(body) @@ -373,11 +380,15 @@ func (c *firewallPoliciesRESTClient) AddRule(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // CloneRules copies rules to the specified firewall policy. -func (c *firewallPoliciesRESTClient) CloneRules(ctx context.Context, req *computepb.CloneRulesFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) CloneRules(ctx context.Context, req *computepb.CloneRulesFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/firewallPolicies/%v/cloneRules", req.GetFirewallPolicy()) @@ -420,11 +431,15 @@ func (c *firewallPoliciesRESTClient) CloneRules(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified policy. -func (c *firewallPoliciesRESTClient) Delete(ctx context.Context, req *computepb.DeleteFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) Delete(ctx context.Context, req *computepb.DeleteFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/firewallPolicies/%v", req.GetFirewallPolicy()) @@ -464,7 +479,11 @@ func (c *firewallPoliciesRESTClient) Delete(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified firewall policy. @@ -637,7 +656,7 @@ func (c *firewallPoliciesRESTClient) GetRule(ctx context.Context, req *computepb } // Insert creates a new policy in the specified project using the data included in the request. -func (c *firewallPoliciesRESTClient) Insert(ctx context.Context, req *computepb.InsertFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) Insert(ctx context.Context, req *computepb.InsertFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetFirewallPolicyResource() jsonReq, err := m.Marshal(body) @@ -687,66 +706,98 @@ func (c *firewallPoliciesRESTClient) Insert(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List lists all the policies that have been configured for the specified project. -func (c *firewallPoliciesRESTClient) List(ctx context.Context, req *computepb.ListFirewallPoliciesRequest, opts ...gax.CallOption) (*computepb.FirewallPolicyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/firewallPolicies") - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ParentId != nil { - params.Add("parentId", fmt.Sprintf("%v", req.GetParentId())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List lists all the policies that have been configured for the specified project. +func (c *firewallPoliciesRESTClient) List(ctx context.Context, req *computepb.ListFirewallPoliciesRequest, opts ...gax.CallOption) *FirewallPolicyIterator { + it := &FirewallPolicyIterator{} + req = proto.Clone(req).(*computepb.ListFirewallPoliciesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.FirewallPolicyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.FirewallPolicy, string, error) { + resp := &computepb.FirewallPolicyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/firewallPolicies") + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ParentId != nil { + params.Add("parentId", fmt.Sprintf("%v", req.GetParentId())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListAssociations lists associations of a specified target, i.e., organization or folder. @@ -794,7 +845,7 @@ func (c *firewallPoliciesRESTClient) ListAssociations(ctx context.Context, req * } // Move moves the specified firewall policy. -func (c *firewallPoliciesRESTClient) Move(ctx context.Context, req *computepb.MoveFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) Move(ctx context.Context, req *computepb.MoveFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/firewallPolicies/%v/move", req.GetFirewallPolicy()) @@ -837,11 +888,15 @@ func (c *firewallPoliciesRESTClient) Move(ctx context.Context, req *computepb.Mo unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Patch patches the specified policy with the data included in the request. -func (c *firewallPoliciesRESTClient) Patch(ctx context.Context, req *computepb.PatchFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) Patch(ctx context.Context, req *computepb.PatchFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetFirewallPolicyResource() jsonReq, err := m.Marshal(body) @@ -888,11 +943,15 @@ func (c *firewallPoliciesRESTClient) Patch(ctx context.Context, req *computepb.P unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // PatchRule patches a rule of the specified priority. -func (c *firewallPoliciesRESTClient) PatchRule(ctx context.Context, req *computepb.PatchRuleFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) PatchRule(ctx context.Context, req *computepb.PatchRuleFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetFirewallPolicyRuleResource() jsonReq, err := m.Marshal(body) @@ -942,11 +1001,15 @@ func (c *firewallPoliciesRESTClient) PatchRule(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // RemoveAssociation removes an association for the specified firewall policy. -func (c *firewallPoliciesRESTClient) RemoveAssociation(ctx context.Context, req *computepb.RemoveAssociationFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) RemoveAssociation(ctx context.Context, req *computepb.RemoveAssociationFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/firewallPolicies/%v/removeAssociation", req.GetFirewallPolicy()) @@ -989,11 +1052,15 @@ func (c *firewallPoliciesRESTClient) RemoveAssociation(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // RemoveRule deletes a rule of the specified priority. -func (c *firewallPoliciesRESTClient) RemoveRule(ctx context.Context, req *computepb.RemoveRuleFirewallPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallPoliciesRESTClient) RemoveRule(ctx context.Context, req *computepb.RemoveRuleFirewallPolicyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/firewallPolicies/%v/removeRule", req.GetFirewallPolicy()) @@ -1036,7 +1103,11 @@ func (c *firewallPoliciesRESTClient) RemoveRule(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -1126,3 +1197,50 @@ func (c *firewallPoliciesRESTClient) TestIamPermissions(ctx context.Context, req return rsp, unm.Unmarshal(buf, rsp) } + +// FirewallPolicyIterator manages a stream of *computepb.FirewallPolicy. +type FirewallPolicyIterator struct { + items []*computepb.FirewallPolicy + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.FirewallPolicy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *FirewallPolicyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *FirewallPolicyIterator) Next() (*computepb.FirewallPolicy, error) { + var item *computepb.FirewallPolicy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *FirewallPolicyIterator) bufLen() int { + return len(it.items) +} + +func (it *FirewallPolicyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/firewall_policies_client_example_test.go b/compute/apiv1/firewall_policies_client_example_test.go index 787e486ebd1..9d43e401e37 100644 --- a/compute/apiv1/firewall_policies_client_example_test.go +++ b/compute/apiv1/firewall_policies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -217,12 +218,18 @@ func ExampleFirewallPoliciesClient_List() { req := &computepb.ListFirewallPoliciesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleFirewallPoliciesClient_ListAssociations() { diff --git a/compute/apiv1/firewalls_client.go b/compute/apiv1/firewalls_client.go index f5d6219fd96..1777197e10a 100644 --- a/compute/apiv1/firewalls_client.go +++ b/compute/apiv1/firewalls_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newFirewallsClientHook clientHook @@ -51,12 +54,12 @@ type internalFirewallsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteFirewallRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteFirewallRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetFirewallRequest, ...gax.CallOption) (*computepb.Firewall, error) - Insert(context.Context, *computepb.InsertFirewallRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListFirewallsRequest, ...gax.CallOption) (*computepb.FirewallList, error) - Patch(context.Context, *computepb.PatchFirewallRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateFirewallRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertFirewallRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListFirewallsRequest, ...gax.CallOption) *FirewallIterator + Patch(context.Context, *computepb.PatchFirewallRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateFirewallRequest, ...gax.CallOption) (*Operation, error) } // FirewallsClient is a client for interacting with Google Compute Engine API. @@ -94,7 +97,7 @@ func (c *FirewallsClient) Connection() *grpc.ClientConn { } // Delete deletes the specified firewall. -func (c *FirewallsClient) Delete(ctx context.Context, req *computepb.DeleteFirewallRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallsClient) Delete(ctx context.Context, req *computepb.DeleteFirewallRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -104,22 +107,22 @@ func (c *FirewallsClient) Get(ctx context.Context, req *computepb.GetFirewallReq } // Insert creates a firewall rule in the specified project using the data included in the request. -func (c *FirewallsClient) Insert(ctx context.Context, req *computepb.InsertFirewallRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallsClient) Insert(ctx context.Context, req *computepb.InsertFirewallRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of firewall rules available to the specified project. -func (c *FirewallsClient) List(ctx context.Context, req *computepb.ListFirewallsRequest, opts ...gax.CallOption) (*computepb.FirewallList, error) { +func (c *FirewallsClient) List(ctx context.Context, req *computepb.ListFirewallsRequest, opts ...gax.CallOption) *FirewallIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates the specified firewall rule with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *FirewallsClient) Patch(ctx context.Context, req *computepb.PatchFirewallRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallsClient) Patch(ctx context.Context, req *computepb.PatchFirewallRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // Update updates the specified firewall rule with the data included in the request. Note that all fields will be updated if using PUT, even fields that are not specified. To update individual fields, please use PATCH instead. -func (c *FirewallsClient) Update(ctx context.Context, req *computepb.UpdateFirewallRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *FirewallsClient) Update(ctx context.Context, req *computepb.UpdateFirewallRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -188,7 +191,7 @@ func (c *firewallsRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified firewall. -func (c *firewallsRESTClient) Delete(ctx context.Context, req *computepb.DeleteFirewallRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallsRESTClient) Delete(ctx context.Context, req *computepb.DeleteFirewallRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/firewalls/%v", req.GetProject(), req.GetFirewall()) @@ -228,7 +231,11 @@ func (c *firewallsRESTClient) Delete(ctx context.Context, req *computepb.DeleteF unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified firewall. @@ -269,7 +276,7 @@ func (c *firewallsRESTClient) Get(ctx context.Context, req *computepb.GetFirewal } // Insert creates a firewall rule in the specified project using the data included in the request. -func (c *firewallsRESTClient) Insert(ctx context.Context, req *computepb.InsertFirewallRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallsRESTClient) Insert(ctx context.Context, req *computepb.InsertFirewallRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetFirewallResource() jsonReq, err := m.Marshal(body) @@ -316,67 +323,99 @@ func (c *firewallsRESTClient) Insert(ctx context.Context, req *computepb.InsertF unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of firewall rules available to the specified project. -func (c *firewallsRESTClient) List(ctx context.Context, req *computepb.ListFirewallsRequest, opts ...gax.CallOption) (*computepb.FirewallList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/firewalls", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of firewall rules available to the specified project. +func (c *firewallsRESTClient) List(ctx context.Context, req *computepb.ListFirewallsRequest, opts ...gax.CallOption) *FirewallIterator { + it := &FirewallIterator{} + req = proto.Clone(req).(*computepb.ListFirewallsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.FirewallList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Firewall, string, error) { + resp := &computepb.FirewallList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/firewalls", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates the specified firewall rule with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *firewallsRESTClient) Patch(ctx context.Context, req *computepb.PatchFirewallRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallsRESTClient) Patch(ctx context.Context, req *computepb.PatchFirewallRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetFirewallResource() jsonReq, err := m.Marshal(body) @@ -423,11 +462,15 @@ func (c *firewallsRESTClient) Patch(ctx context.Context, req *computepb.PatchFir unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates the specified firewall rule with the data included in the request. Note that all fields will be updated if using PUT, even fields that are not specified. To update individual fields, please use PATCH instead. -func (c *firewallsRESTClient) Update(ctx context.Context, req *computepb.UpdateFirewallRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *firewallsRESTClient) Update(ctx context.Context, req *computepb.UpdateFirewallRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetFirewallResource() jsonReq, err := m.Marshal(body) @@ -474,5 +517,56 @@ func (c *firewallsRESTClient) Update(ctx context.Context, req *computepb.UpdateF unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// FirewallIterator manages a stream of *computepb.Firewall. +type FirewallIterator struct { + items []*computepb.Firewall + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Firewall, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *FirewallIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *FirewallIterator) Next() (*computepb.Firewall, error) { + var item *computepb.Firewall + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *FirewallIterator) bufLen() int { + return len(it.items) +} + +func (it *FirewallIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/firewalls_client_example_test.go b/compute/apiv1/firewalls_client_example_test.go index e1db038fb2e..50e66a22ec0 100644 --- a/compute/apiv1/firewalls_client_example_test.go +++ b/compute/apiv1/firewalls_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleFirewallsClient_List() { req := &computepb.ListFirewallsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleFirewallsClient_Patch() { diff --git a/compute/apiv1/forwarding_rules_client.go b/compute/apiv1/forwarding_rules_client.go index 6a5c52e2ac4..ea3d88eedbb 100644 --- a/compute/apiv1/forwarding_rules_client.go +++ b/compute/apiv1/forwarding_rules_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newForwardingRulesClientHook clientHook @@ -53,14 +57,14 @@ type internalForwardingRulesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListForwardingRulesRequest, ...gax.CallOption) (*computepb.ForwardingRuleAggregatedList, error) - Delete(context.Context, *computepb.DeleteForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListForwardingRulesRequest, ...gax.CallOption) *ForwardingRulesScopedListPairIterator + Delete(context.Context, *computepb.DeleteForwardingRuleRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetForwardingRuleRequest, ...gax.CallOption) (*computepb.ForwardingRule, error) - Insert(context.Context, *computepb.InsertForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListForwardingRulesRequest, ...gax.CallOption) (*computepb.ForwardingRuleList, error) - Patch(context.Context, *computepb.PatchForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) - SetLabels(context.Context, *computepb.SetLabelsForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) - SetTarget(context.Context, *computepb.SetTargetForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertForwardingRuleRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListForwardingRulesRequest, ...gax.CallOption) *ForwardingRuleIterator + Patch(context.Context, *computepb.PatchForwardingRuleRequest, ...gax.CallOption) (*Operation, error) + SetLabels(context.Context, *computepb.SetLabelsForwardingRuleRequest, ...gax.CallOption) (*Operation, error) + SetTarget(context.Context, *computepb.SetTargetForwardingRuleRequest, ...gax.CallOption) (*Operation, error) } // ForwardingRulesClient is a client for interacting with Google Compute Engine API. @@ -98,12 +102,12 @@ func (c *ForwardingRulesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of forwarding rules. -func (c *ForwardingRulesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListForwardingRulesRequest, opts ...gax.CallOption) (*computepb.ForwardingRuleAggregatedList, error) { +func (c *ForwardingRulesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListForwardingRulesRequest, opts ...gax.CallOption) *ForwardingRulesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified ForwardingRule resource. -func (c *ForwardingRulesClient) Delete(ctx context.Context, req *computepb.DeleteForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ForwardingRulesClient) Delete(ctx context.Context, req *computepb.DeleteForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -113,27 +117,27 @@ func (c *ForwardingRulesClient) Get(ctx context.Context, req *computepb.GetForwa } // Insert creates a ForwardingRule resource in the specified project and region using the data included in the request. -func (c *ForwardingRulesClient) Insert(ctx context.Context, req *computepb.InsertForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ForwardingRulesClient) Insert(ctx context.Context, req *computepb.InsertForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of ForwardingRule resources available to the specified project and region. -func (c *ForwardingRulesClient) List(ctx context.Context, req *computepb.ListForwardingRulesRequest, opts ...gax.CallOption) (*computepb.ForwardingRuleList, error) { +func (c *ForwardingRulesClient) List(ctx context.Context, req *computepb.ListForwardingRulesRequest, opts ...gax.CallOption) *ForwardingRuleIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates the specified forwarding rule with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. Currently, you can only patch the network_tier field. -func (c *ForwardingRulesClient) Patch(ctx context.Context, req *computepb.PatchForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ForwardingRulesClient) Patch(ctx context.Context, req *computepb.PatchForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // SetLabels sets the labels on the specified resource. To learn more about labels, read the Labeling Resources documentation. -func (c *ForwardingRulesClient) SetLabels(ctx context.Context, req *computepb.SetLabelsForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ForwardingRulesClient) SetLabels(ctx context.Context, req *computepb.SetLabelsForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetLabels(ctx, req, opts...) } // SetTarget changes target URL for forwarding rule. The new target should be of the same type as the old target. -func (c *ForwardingRulesClient) SetTarget(ctx context.Context, req *computepb.SetTargetForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ForwardingRulesClient) SetTarget(ctx context.Context, req *computepb.SetTargetForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetTarget(ctx, req, opts...) } @@ -202,66 +206,101 @@ func (c *forwardingRulesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of forwarding rules. -func (c *forwardingRulesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListForwardingRulesRequest, opts ...gax.CallOption) (*computepb.ForwardingRuleAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/forwardingRules", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *forwardingRulesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListForwardingRulesRequest, opts ...gax.CallOption) *ForwardingRulesScopedListPairIterator { + it := &ForwardingRulesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListForwardingRulesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ForwardingRuleAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]ForwardingRulesScopedListPair, string, error) { + resp := &computepb.ForwardingRuleAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/forwardingRules", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]ForwardingRulesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, ForwardingRulesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified ForwardingRule resource. -func (c *forwardingRulesRESTClient) Delete(ctx context.Context, req *computepb.DeleteForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *forwardingRulesRESTClient) Delete(ctx context.Context, req *computepb.DeleteForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/forwardingRules/%v", req.GetProject(), req.GetRegion(), req.GetForwardingRule()) @@ -301,7 +340,11 @@ func (c *forwardingRulesRESTClient) Delete(ctx context.Context, req *computepb.D unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified ForwardingRule resource. @@ -342,7 +385,7 @@ func (c *forwardingRulesRESTClient) Get(ctx context.Context, req *computepb.GetF } // Insert creates a ForwardingRule resource in the specified project and region using the data included in the request. -func (c *forwardingRulesRESTClient) Insert(ctx context.Context, req *computepb.InsertForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *forwardingRulesRESTClient) Insert(ctx context.Context, req *computepb.InsertForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetForwardingRuleResource() jsonReq, err := m.Marshal(body) @@ -389,67 +432,99 @@ func (c *forwardingRulesRESTClient) Insert(ctx context.Context, req *computepb.I unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of ForwardingRule resources available to the specified project and region. -func (c *forwardingRulesRESTClient) List(ctx context.Context, req *computepb.ListForwardingRulesRequest, opts ...gax.CallOption) (*computepb.ForwardingRuleList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/forwardingRules", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of ForwardingRule resources available to the specified project and region. +func (c *forwardingRulesRESTClient) List(ctx context.Context, req *computepb.ListForwardingRulesRequest, opts ...gax.CallOption) *ForwardingRuleIterator { + it := &ForwardingRuleIterator{} + req = proto.Clone(req).(*computepb.ListForwardingRulesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ForwardingRuleList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.ForwardingRule, string, error) { + resp := &computepb.ForwardingRuleList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/forwardingRules", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates the specified forwarding rule with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. Currently, you can only patch the network_tier field. -func (c *forwardingRulesRESTClient) Patch(ctx context.Context, req *computepb.PatchForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *forwardingRulesRESTClient) Patch(ctx context.Context, req *computepb.PatchForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetForwardingRuleResource() jsonReq, err := m.Marshal(body) @@ -496,11 +571,15 @@ func (c *forwardingRulesRESTClient) Patch(ctx context.Context, req *computepb.Pa unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetLabels sets the labels on the specified resource. To learn more about labels, read the Labeling Resources documentation. -func (c *forwardingRulesRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *forwardingRulesRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionSetLabelsRequestResource() jsonReq, err := m.Marshal(body) @@ -547,11 +626,15 @@ func (c *forwardingRulesRESTClient) SetLabels(ctx context.Context, req *computep unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetTarget changes target URL for forwarding rule. The new target should be of the same type as the old target. -func (c *forwardingRulesRESTClient) SetTarget(ctx context.Context, req *computepb.SetTargetForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *forwardingRulesRESTClient) SetTarget(ctx context.Context, req *computepb.SetTargetForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetReferenceResource() jsonReq, err := m.Marshal(body) @@ -598,5 +681,109 @@ func (c *forwardingRulesRESTClient) SetTarget(ctx context.Context, req *computep unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// ForwardingRuleIterator manages a stream of *computepb.ForwardingRule. +type ForwardingRuleIterator struct { + items []*computepb.ForwardingRule + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.ForwardingRule, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ForwardingRuleIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ForwardingRuleIterator) Next() (*computepb.ForwardingRule, error) { + var item *computepb.ForwardingRule + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ForwardingRuleIterator) bufLen() int { + return len(it.items) +} + +func (it *ForwardingRuleIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ForwardingRulesScopedListPair is a holder type for string/*computepb.ForwardingRulesScopedList map entries +type ForwardingRulesScopedListPair struct { + Key string + Value *computepb.ForwardingRulesScopedList +} + +// ForwardingRulesScopedListPairIterator manages a stream of ForwardingRulesScopedListPair. +type ForwardingRulesScopedListPairIterator struct { + items []ForwardingRulesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []ForwardingRulesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ForwardingRulesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ForwardingRulesScopedListPairIterator) Next() (ForwardingRulesScopedListPair, error) { + var item ForwardingRulesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ForwardingRulesScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *ForwardingRulesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/forwarding_rules_client_example_test.go b/compute/apiv1/forwarding_rules_client_example_test.go index 1a2a9a5495f..fdc2d9eebc9 100644 --- a/compute/apiv1/forwarding_rules_client_example_test.go +++ b/compute/apiv1/forwarding_rules_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleForwardingRulesClient_AggregatedList() { req := &computepb.AggregatedListForwardingRulesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleForwardingRulesClient_Delete() { @@ -122,12 +129,18 @@ func ExampleForwardingRulesClient_List() { req := &computepb.ListForwardingRulesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleForwardingRulesClient_Patch() { diff --git a/compute/apiv1/global_addresses_client.go b/compute/apiv1/global_addresses_client.go index fc6b425a873..40c0595fced 100644 --- a/compute/apiv1/global_addresses_client.go +++ b/compute/apiv1/global_addresses_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newGlobalAddressesClientHook clientHook @@ -49,10 +52,10 @@ type internalGlobalAddressesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteGlobalAddressRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteGlobalAddressRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetGlobalAddressRequest, ...gax.CallOption) (*computepb.Address, error) - Insert(context.Context, *computepb.InsertGlobalAddressRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListGlobalAddressesRequest, ...gax.CallOption) (*computepb.AddressList, error) + Insert(context.Context, *computepb.InsertGlobalAddressRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListGlobalAddressesRequest, ...gax.CallOption) *AddressIterator } // GlobalAddressesClient is a client for interacting with Google Compute Engine API. @@ -90,7 +93,7 @@ func (c *GlobalAddressesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified address resource. -func (c *GlobalAddressesClient) Delete(ctx context.Context, req *computepb.DeleteGlobalAddressRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalAddressesClient) Delete(ctx context.Context, req *computepb.DeleteGlobalAddressRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -100,12 +103,12 @@ func (c *GlobalAddressesClient) Get(ctx context.Context, req *computepb.GetGloba } // Insert creates an address resource in the specified project by using the data included in the request. -func (c *GlobalAddressesClient) Insert(ctx context.Context, req *computepb.InsertGlobalAddressRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalAddressesClient) Insert(ctx context.Context, req *computepb.InsertGlobalAddressRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of global addresses. -func (c *GlobalAddressesClient) List(ctx context.Context, req *computepb.ListGlobalAddressesRequest, opts ...gax.CallOption) (*computepb.AddressList, error) { +func (c *GlobalAddressesClient) List(ctx context.Context, req *computepb.ListGlobalAddressesRequest, opts ...gax.CallOption) *AddressIterator { return c.internalClient.List(ctx, req, opts...) } @@ -174,7 +177,7 @@ func (c *globalAddressesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified address resource. -func (c *globalAddressesRESTClient) Delete(ctx context.Context, req *computepb.DeleteGlobalAddressRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalAddressesRESTClient) Delete(ctx context.Context, req *computepb.DeleteGlobalAddressRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/addresses/%v", req.GetProject(), req.GetAddress()) @@ -214,7 +217,11 @@ func (c *globalAddressesRESTClient) Delete(ctx context.Context, req *computepb.D unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified address resource. Gets a list of available addresses by making a list() request. @@ -255,7 +262,7 @@ func (c *globalAddressesRESTClient) Get(ctx context.Context, req *computepb.GetG } // Insert creates an address resource in the specified project by using the data included in the request. -func (c *globalAddressesRESTClient) Insert(ctx context.Context, req *computepb.InsertGlobalAddressRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalAddressesRESTClient) Insert(ctx context.Context, req *computepb.InsertGlobalAddressRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAddressResource() jsonReq, err := m.Marshal(body) @@ -302,61 +309,93 @@ func (c *globalAddressesRESTClient) Insert(ctx context.Context, req *computepb.I unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of global addresses. -func (c *globalAddressesRESTClient) List(ctx context.Context, req *computepb.ListGlobalAddressesRequest, opts ...gax.CallOption) (*computepb.AddressList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/addresses", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() + op := &Operation{proto: rsp} + return op, err +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +// List retrieves a list of global addresses. +func (c *globalAddressesRESTClient) List(ctx context.Context, req *computepb.ListGlobalAddressesRequest, opts ...gax.CallOption) *AddressIterator { + it := &AddressIterator{} + req = proto.Clone(req).(*computepb.ListGlobalAddressesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Address, string, error) { + resp := &computepb.AddressList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/addresses", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.AddressList{} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - return rsp, unm.Unmarshal(buf, rsp) + return it } diff --git a/compute/apiv1/global_addresses_client_example_test.go b/compute/apiv1/global_addresses_client_example_test.go index a226879e957..945876f07e0 100644 --- a/compute/apiv1/global_addresses_client_example_test.go +++ b/compute/apiv1/global_addresses_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,10 +104,16 @@ func ExampleGlobalAddressesClient_List() { req := &computepb.ListGlobalAddressesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/global_forwarding_rules_client.go b/compute/apiv1/global_forwarding_rules_client.go index b230bc65599..6f0a2e05449 100644 --- a/compute/apiv1/global_forwarding_rules_client.go +++ b/compute/apiv1/global_forwarding_rules_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newGlobalForwardingRulesClientHook clientHook @@ -52,13 +55,13 @@ type internalGlobalForwardingRulesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteGlobalForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteGlobalForwardingRuleRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetGlobalForwardingRuleRequest, ...gax.CallOption) (*computepb.ForwardingRule, error) - Insert(context.Context, *computepb.InsertGlobalForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListGlobalForwardingRulesRequest, ...gax.CallOption) (*computepb.ForwardingRuleList, error) - Patch(context.Context, *computepb.PatchGlobalForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) - SetLabels(context.Context, *computepb.SetLabelsGlobalForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) - SetTarget(context.Context, *computepb.SetTargetGlobalForwardingRuleRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertGlobalForwardingRuleRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListGlobalForwardingRulesRequest, ...gax.CallOption) *ForwardingRuleIterator + Patch(context.Context, *computepb.PatchGlobalForwardingRuleRequest, ...gax.CallOption) (*Operation, error) + SetLabels(context.Context, *computepb.SetLabelsGlobalForwardingRuleRequest, ...gax.CallOption) (*Operation, error) + SetTarget(context.Context, *computepb.SetTargetGlobalForwardingRuleRequest, ...gax.CallOption) (*Operation, error) } // GlobalForwardingRulesClient is a client for interacting with Google Compute Engine API. @@ -96,7 +99,7 @@ func (c *GlobalForwardingRulesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified GlobalForwardingRule resource. -func (c *GlobalForwardingRulesClient) Delete(ctx context.Context, req *computepb.DeleteGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalForwardingRulesClient) Delete(ctx context.Context, req *computepb.DeleteGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -106,27 +109,27 @@ func (c *GlobalForwardingRulesClient) Get(ctx context.Context, req *computepb.Ge } // Insert creates a GlobalForwardingRule resource in the specified project using the data included in the request. -func (c *GlobalForwardingRulesClient) Insert(ctx context.Context, req *computepb.InsertGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalForwardingRulesClient) Insert(ctx context.Context, req *computepb.InsertGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of GlobalForwardingRule resources available to the specified project. -func (c *GlobalForwardingRulesClient) List(ctx context.Context, req *computepb.ListGlobalForwardingRulesRequest, opts ...gax.CallOption) (*computepb.ForwardingRuleList, error) { +func (c *GlobalForwardingRulesClient) List(ctx context.Context, req *computepb.ListGlobalForwardingRulesRequest, opts ...gax.CallOption) *ForwardingRuleIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates the specified forwarding rule with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. Currently, you can only patch the network_tier field. -func (c *GlobalForwardingRulesClient) Patch(ctx context.Context, req *computepb.PatchGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalForwardingRulesClient) Patch(ctx context.Context, req *computepb.PatchGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // SetLabels sets the labels on the specified resource. To learn more about labels, read the Labeling Resources documentation. -func (c *GlobalForwardingRulesClient) SetLabels(ctx context.Context, req *computepb.SetLabelsGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalForwardingRulesClient) SetLabels(ctx context.Context, req *computepb.SetLabelsGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetLabels(ctx, req, opts...) } // SetTarget changes target URL for the GlobalForwardingRule resource. The new target should be of the same type as the old target. -func (c *GlobalForwardingRulesClient) SetTarget(ctx context.Context, req *computepb.SetTargetGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalForwardingRulesClient) SetTarget(ctx context.Context, req *computepb.SetTargetGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetTarget(ctx, req, opts...) } @@ -195,7 +198,7 @@ func (c *globalForwardingRulesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified GlobalForwardingRule resource. -func (c *globalForwardingRulesRESTClient) Delete(ctx context.Context, req *computepb.DeleteGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalForwardingRulesRESTClient) Delete(ctx context.Context, req *computepb.DeleteGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/forwardingRules/%v", req.GetProject(), req.GetForwardingRule()) @@ -235,7 +238,11 @@ func (c *globalForwardingRulesRESTClient) Delete(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified GlobalForwardingRule resource. Gets a list of available forwarding rules by making a list() request. @@ -276,7 +283,7 @@ func (c *globalForwardingRulesRESTClient) Get(ctx context.Context, req *computep } // Insert creates a GlobalForwardingRule resource in the specified project using the data included in the request. -func (c *globalForwardingRulesRESTClient) Insert(ctx context.Context, req *computepb.InsertGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalForwardingRulesRESTClient) Insert(ctx context.Context, req *computepb.InsertGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetForwardingRuleResource() jsonReq, err := m.Marshal(body) @@ -323,67 +330,99 @@ func (c *globalForwardingRulesRESTClient) Insert(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of GlobalForwardingRule resources available to the specified project. -func (c *globalForwardingRulesRESTClient) List(ctx context.Context, req *computepb.ListGlobalForwardingRulesRequest, opts ...gax.CallOption) (*computepb.ForwardingRuleList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/forwardingRules", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of GlobalForwardingRule resources available to the specified project. +func (c *globalForwardingRulesRESTClient) List(ctx context.Context, req *computepb.ListGlobalForwardingRulesRequest, opts ...gax.CallOption) *ForwardingRuleIterator { + it := &ForwardingRuleIterator{} + req = proto.Clone(req).(*computepb.ListGlobalForwardingRulesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ForwardingRuleList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.ForwardingRule, string, error) { + resp := &computepb.ForwardingRuleList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/forwardingRules", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates the specified forwarding rule with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. Currently, you can only patch the network_tier field. -func (c *globalForwardingRulesRESTClient) Patch(ctx context.Context, req *computepb.PatchGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalForwardingRulesRESTClient) Patch(ctx context.Context, req *computepb.PatchGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetForwardingRuleResource() jsonReq, err := m.Marshal(body) @@ -430,11 +469,15 @@ func (c *globalForwardingRulesRESTClient) Patch(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetLabels sets the labels on the specified resource. To learn more about labels, read the Labeling Resources documentation. -func (c *globalForwardingRulesRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalForwardingRulesRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetGlobalSetLabelsRequestResource() jsonReq, err := m.Marshal(body) @@ -474,11 +517,15 @@ func (c *globalForwardingRulesRESTClient) SetLabels(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetTarget changes target URL for the GlobalForwardingRule resource. The new target should be of the same type as the old target. -func (c *globalForwardingRulesRESTClient) SetTarget(ctx context.Context, req *computepb.SetTargetGlobalForwardingRuleRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalForwardingRulesRESTClient) SetTarget(ctx context.Context, req *computepb.SetTargetGlobalForwardingRuleRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetReferenceResource() jsonReq, err := m.Marshal(body) @@ -525,5 +572,9 @@ func (c *globalForwardingRulesRESTClient) SetTarget(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } diff --git a/compute/apiv1/global_forwarding_rules_client_example_test.go b/compute/apiv1/global_forwarding_rules_client_example_test.go index 13f8bce3d6b..91d97c357a9 100644 --- a/compute/apiv1/global_forwarding_rules_client_example_test.go +++ b/compute/apiv1/global_forwarding_rules_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleGlobalForwardingRulesClient_List() { req := &computepb.ListGlobalForwardingRulesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleGlobalForwardingRulesClient_Patch() { diff --git a/compute/apiv1/global_network_endpoint_groups_client.go b/compute/apiv1/global_network_endpoint_groups_client.go index 8591df90da4..e6e8f49bd6a 100644 --- a/compute/apiv1/global_network_endpoint_groups_client.go +++ b/compute/apiv1/global_network_endpoint_groups_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newGlobalNetworkEndpointGroupsClientHook clientHook @@ -52,13 +55,13 @@ type internalGlobalNetworkEndpointGroupsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AttachNetworkEndpoints(context.Context, *computepb.AttachNetworkEndpointsGlobalNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteGlobalNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - DetachNetworkEndpoints(context.Context, *computepb.DetachNetworkEndpointsGlobalNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) + AttachNetworkEndpoints(context.Context, *computepb.AttachNetworkEndpointsGlobalNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteGlobalNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) + DetachNetworkEndpoints(context.Context, *computepb.DetachNetworkEndpointsGlobalNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetGlobalNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.NetworkEndpointGroup, error) - Insert(context.Context, *computepb.InsertGlobalNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListGlobalNetworkEndpointGroupsRequest, ...gax.CallOption) (*computepb.NetworkEndpointGroupList, error) - ListNetworkEndpoints(context.Context, *computepb.ListNetworkEndpointsGlobalNetworkEndpointGroupsRequest, ...gax.CallOption) (*computepb.NetworkEndpointGroupsListNetworkEndpoints, error) + Insert(context.Context, *computepb.InsertGlobalNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListGlobalNetworkEndpointGroupsRequest, ...gax.CallOption) *NetworkEndpointGroupIterator + ListNetworkEndpoints(context.Context, *computepb.ListNetworkEndpointsGlobalNetworkEndpointGroupsRequest, ...gax.CallOption) *NetworkEndpointWithHealthStatusIterator } // GlobalNetworkEndpointGroupsClient is a client for interacting with Google Compute Engine API. @@ -96,17 +99,17 @@ func (c *GlobalNetworkEndpointGroupsClient) Connection() *grpc.ClientConn { } // AttachNetworkEndpoints attach a network endpoint to the specified network endpoint group. -func (c *GlobalNetworkEndpointGroupsClient) AttachNetworkEndpoints(ctx context.Context, req *computepb.AttachNetworkEndpointsGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalNetworkEndpointGroupsClient) AttachNetworkEndpoints(ctx context.Context, req *computepb.AttachNetworkEndpointsGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AttachNetworkEndpoints(ctx, req, opts...) } // Delete deletes the specified network endpoint group.Note that the NEG cannot be deleted if there are backend services referencing it. -func (c *GlobalNetworkEndpointGroupsClient) Delete(ctx context.Context, req *computepb.DeleteGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalNetworkEndpointGroupsClient) Delete(ctx context.Context, req *computepb.DeleteGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } // DetachNetworkEndpoints detach the network endpoint from the specified network endpoint group. -func (c *GlobalNetworkEndpointGroupsClient) DetachNetworkEndpoints(ctx context.Context, req *computepb.DetachNetworkEndpointsGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalNetworkEndpointGroupsClient) DetachNetworkEndpoints(ctx context.Context, req *computepb.DetachNetworkEndpointsGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DetachNetworkEndpoints(ctx, req, opts...) } @@ -116,17 +119,17 @@ func (c *GlobalNetworkEndpointGroupsClient) Get(ctx context.Context, req *comput } // Insert creates a network endpoint group in the specified project using the parameters that are included in the request. -func (c *GlobalNetworkEndpointGroupsClient) Insert(ctx context.Context, req *computepb.InsertGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalNetworkEndpointGroupsClient) Insert(ctx context.Context, req *computepb.InsertGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of network endpoint groups that are located in the specified project. -func (c *GlobalNetworkEndpointGroupsClient) List(ctx context.Context, req *computepb.ListGlobalNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupList, error) { +func (c *GlobalNetworkEndpointGroupsClient) List(ctx context.Context, req *computepb.ListGlobalNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointGroupIterator { return c.internalClient.List(ctx, req, opts...) } // ListNetworkEndpoints lists the network endpoints in the specified network endpoint group. -func (c *GlobalNetworkEndpointGroupsClient) ListNetworkEndpoints(ctx context.Context, req *computepb.ListNetworkEndpointsGlobalNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupsListNetworkEndpoints, error) { +func (c *GlobalNetworkEndpointGroupsClient) ListNetworkEndpoints(ctx context.Context, req *computepb.ListNetworkEndpointsGlobalNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointWithHealthStatusIterator { return c.internalClient.ListNetworkEndpoints(ctx, req, opts...) } @@ -195,7 +198,7 @@ func (c *globalNetworkEndpointGroupsRESTClient) Connection() *grpc.ClientConn { } // AttachNetworkEndpoints attach a network endpoint to the specified network endpoint group. -func (c *globalNetworkEndpointGroupsRESTClient) AttachNetworkEndpoints(ctx context.Context, req *computepb.AttachNetworkEndpointsGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalNetworkEndpointGroupsRESTClient) AttachNetworkEndpoints(ctx context.Context, req *computepb.AttachNetworkEndpointsGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetGlobalNetworkEndpointGroupsAttachEndpointsRequestResource() jsonReq, err := m.Marshal(body) @@ -242,11 +245,15 @@ func (c *globalNetworkEndpointGroupsRESTClient) AttachNetworkEndpoints(ctx conte unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified network endpoint group.Note that the NEG cannot be deleted if there are backend services referencing it. -func (c *globalNetworkEndpointGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalNetworkEndpointGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networkEndpointGroups/%v", req.GetProject(), req.GetNetworkEndpointGroup()) @@ -286,11 +293,15 @@ func (c *globalNetworkEndpointGroupsRESTClient) Delete(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DetachNetworkEndpoints detach the network endpoint from the specified network endpoint group. -func (c *globalNetworkEndpointGroupsRESTClient) DetachNetworkEndpoints(ctx context.Context, req *computepb.DetachNetworkEndpointsGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalNetworkEndpointGroupsRESTClient) DetachNetworkEndpoints(ctx context.Context, req *computepb.DetachNetworkEndpointsGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetGlobalNetworkEndpointGroupsDetachEndpointsRequestResource() jsonReq, err := m.Marshal(body) @@ -337,7 +348,11 @@ func (c *globalNetworkEndpointGroupsRESTClient) DetachNetworkEndpoints(ctx conte unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified network endpoint group. Gets a list of available network endpoint groups by making a list() request. @@ -378,7 +393,7 @@ func (c *globalNetworkEndpointGroupsRESTClient) Get(ctx context.Context, req *co } // Insert creates a network endpoint group in the specified project using the parameters that are included in the request. -func (c *globalNetworkEndpointGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalNetworkEndpointGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertGlobalNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworkEndpointGroupResource() jsonReq, err := m.Marshal(body) @@ -425,117 +440,271 @@ func (c *globalNetworkEndpointGroupsRESTClient) Insert(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of network endpoint groups that are located in the specified project. -func (c *globalNetworkEndpointGroupsRESTClient) List(ctx context.Context, req *computepb.ListGlobalNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networkEndpointGroups", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } + op := &Operation{proto: rsp} + return op, err +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } +// List retrieves the list of network endpoint groups that are located in the specified project. +func (c *globalNetworkEndpointGroupsRESTClient) List(ctx context.Context, req *computepb.ListGlobalNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointGroupIterator { + it := &NetworkEndpointGroupIterator{} + req = proto.Clone(req).(*computepb.ListGlobalNetworkEndpointGroupsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NetworkEndpointGroup, string, error) { + resp := &computepb.NetworkEndpointGroupList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networkEndpointGroups", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it +} +// ListNetworkEndpoints lists the network endpoints in the specified network endpoint group. +func (c *globalNetworkEndpointGroupsRESTClient) ListNetworkEndpoints(ctx context.Context, req *computepb.ListNetworkEndpointsGlobalNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointWithHealthStatusIterator { + it := &NetworkEndpointWithHealthStatusIterator{} + req = proto.Clone(req).(*computepb.ListNetworkEndpointsGlobalNetworkEndpointGroupsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NetworkEndpointGroupList{} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NetworkEndpointWithHealthStatus, string, error) { + resp := &computepb.NetworkEndpointGroupsListNetworkEndpoints{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networkEndpointGroups/%v/listNetworkEndpoints", req.GetProject(), req.GetNetworkEndpointGroup()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it +} - return rsp, unm.Unmarshal(buf, rsp) +// NetworkEndpointGroupIterator manages a stream of *computepb.NetworkEndpointGroup. +type NetworkEndpointGroupIterator struct { + items []*computepb.NetworkEndpointGroup + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.NetworkEndpointGroup, nextPageToken string, err error) } -// ListNetworkEndpoints lists the network endpoints in the specified network endpoint group. -func (c *globalNetworkEndpointGroupsRESTClient) ListNetworkEndpoints(ctx context.Context, req *computepb.ListNetworkEndpointsGlobalNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupsListNetworkEndpoints, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networkEndpointGroups/%v/listNetworkEndpoints", req.GetProject(), req.GetNetworkEndpointGroup()) +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NetworkEndpointGroupIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NetworkEndpointGroupIterator) Next() (*computepb.NetworkEndpointGroup, error) { + var item *computepb.NetworkEndpointGroup + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - baseUrl.RawQuery = params.Encode() +func (it *NetworkEndpointGroupIterator) bufLen() int { + return len(it.items) +} - httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} +func (it *NetworkEndpointGroupIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// NetworkEndpointWithHealthStatusIterator manages a stream of *computepb.NetworkEndpointWithHealthStatus. +type NetworkEndpointWithHealthStatusIterator struct { + items []*computepb.NetworkEndpointWithHealthStatus + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.NetworkEndpointWithHealthStatus, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NetworkEndpointWithHealthStatusIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NetworkEndpointWithHealthStatusIterator) Next() (*computepb.NetworkEndpointWithHealthStatus, error) { + var item *computepb.NetworkEndpointWithHealthStatus + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NetworkEndpointGroupsListNetworkEndpoints{} +func (it *NetworkEndpointWithHealthStatusIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *NetworkEndpointWithHealthStatusIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/global_network_endpoint_groups_client_example_test.go b/compute/apiv1/global_network_endpoint_groups_client_example_test.go index 80361d6d06e..cdb85bf4e9e 100644 --- a/compute/apiv1/global_network_endpoint_groups_client_example_test.go +++ b/compute/apiv1/global_network_endpoint_groups_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -141,12 +142,18 @@ func ExampleGlobalNetworkEndpointGroupsClient_List() { req := &computepb.ListGlobalNetworkEndpointGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleGlobalNetworkEndpointGroupsClient_ListNetworkEndpoints() { @@ -160,10 +167,16 @@ func ExampleGlobalNetworkEndpointGroupsClient_ListNetworkEndpoints() { req := &computepb.ListNetworkEndpointsGlobalNetworkEndpointGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListNetworkEndpoints(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListNetworkEndpoints(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/global_operations_client.go b/compute/apiv1/global_operations_client.go index 9167c8c9d26..5e245ef4c1e 100644 --- a/compute/apiv1/global_operations_client.go +++ b/compute/apiv1/global_operations_client.go @@ -20,10 +20,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newGlobalOperationsClientHook clientHook @@ -49,11 +53,11 @@ type internalGlobalOperationsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListGlobalOperationsRequest, ...gax.CallOption) (*computepb.OperationAggregatedList, error) + AggregatedList(context.Context, *computepb.AggregatedListGlobalOperationsRequest, ...gax.CallOption) *OperationsScopedListPairIterator Delete(context.Context, *computepb.DeleteGlobalOperationRequest, ...gax.CallOption) (*computepb.DeleteGlobalOperationResponse, error) - Get(context.Context, *computepb.GetGlobalOperationRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListGlobalOperationsRequest, ...gax.CallOption) (*computepb.OperationList, error) - Wait(context.Context, *computepb.WaitGlobalOperationRequest, ...gax.CallOption) (*computepb.Operation, error) + Get(context.Context, *computepb.GetGlobalOperationRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListGlobalOperationsRequest, ...gax.CallOption) *OperationIterator + Wait(context.Context, *computepb.WaitGlobalOperationRequest, ...gax.CallOption) (*Operation, error) } // GlobalOperationsClient is a client for interacting with Google Compute Engine API. @@ -91,7 +95,7 @@ func (c *GlobalOperationsClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of all operations. -func (c *GlobalOperationsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListGlobalOperationsRequest, opts ...gax.CallOption) (*computepb.OperationAggregatedList, error) { +func (c *GlobalOperationsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListGlobalOperationsRequest, opts ...gax.CallOption) *OperationsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } @@ -101,12 +105,12 @@ func (c *GlobalOperationsClient) Delete(ctx context.Context, req *computepb.Dele } // Get retrieves the specified Operations resource. Gets a list of operations by making a list() request. -func (c *GlobalOperationsClient) Get(ctx context.Context, req *computepb.GetGlobalOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalOperationsClient) Get(ctx context.Context, req *computepb.GetGlobalOperationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Get(ctx, req, opts...) } // List retrieves a list of Operation resources contained within the specified project. -func (c *GlobalOperationsClient) List(ctx context.Context, req *computepb.ListGlobalOperationsRequest, opts ...gax.CallOption) (*computepb.OperationList, error) { +func (c *GlobalOperationsClient) List(ctx context.Context, req *computepb.ListGlobalOperationsRequest, opts ...gax.CallOption) *OperationIterator { return c.internalClient.List(ctx, req, opts...) } @@ -117,7 +121,7 @@ func (c *GlobalOperationsClient) List(ctx context.Context, req *computepb.ListGl // In uncommon cases, when the server is overloaded, the request might return before the default deadline is reached, or might return after zero seconds. // // If the default deadline is reached, there is no guarantee that the operation is actually done when the method returns. Be prepared to retry if the operation is not DONE. -func (c *GlobalOperationsClient) Wait(ctx context.Context, req *computepb.WaitGlobalOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalOperationsClient) Wait(ctx context.Context, req *computepb.WaitGlobalOperationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Wait(ctx, req, opts...) } @@ -186,62 +190,97 @@ func (c *globalOperationsRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of all operations. -func (c *globalOperationsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListGlobalOperationsRequest, opts ...gax.CallOption) (*computepb.OperationAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/operations", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *globalOperationsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListGlobalOperationsRequest, opts ...gax.CallOption) *OperationsScopedListPairIterator { + it := &OperationsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListGlobalOperationsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.OperationAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]OperationsScopedListPair, string, error) { + resp := &computepb.OperationAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/operations", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]OperationsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, OperationsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified Operations resource. @@ -282,7 +321,7 @@ func (c *globalOperationsRESTClient) Delete(ctx context.Context, req *computepb. } // Get retrieves the specified Operations resource. Gets a list of operations by making a list() request. -func (c *globalOperationsRESTClient) Get(ctx context.Context, req *computepb.GetGlobalOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalOperationsRESTClient) Get(ctx context.Context, req *computepb.GetGlobalOperationRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/operations/%v", req.GetProject(), req.GetOperation()) @@ -315,63 +354,95 @@ func (c *globalOperationsRESTClient) Get(ctx context.Context, req *computepb.Get unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of Operation resources contained within the specified project. -func (c *globalOperationsRESTClient) List(ctx context.Context, req *computepb.ListGlobalOperationsRequest, opts ...gax.CallOption) (*computepb.OperationList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/operations", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of Operation resources contained within the specified project. +func (c *globalOperationsRESTClient) List(ctx context.Context, req *computepb.ListGlobalOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*computepb.ListGlobalOperationsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.OperationList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Operation, string, error) { + resp := &computepb.OperationList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/operations", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Wait waits for the specified Operation resource to return as DONE or for the request to approach the 2 minute deadline, and retrieves the specified Operation resource. This method differs from the GET method in that it waits for no more than the default deadline (2 minutes) and then returns the current state of the operation, which might be DONE or still in progress. @@ -381,7 +452,7 @@ func (c *globalOperationsRESTClient) List(ctx context.Context, req *computepb.Li // In uncommon cases, when the server is overloaded, the request might return before the default deadline is reached, or might return after zero seconds. // // If the default deadline is reached, there is no guarantee that the operation is actually done when the method returns. Be prepared to retry if the operation is not DONE. -func (c *globalOperationsRESTClient) Wait(ctx context.Context, req *computepb.WaitGlobalOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalOperationsRESTClient) Wait(ctx context.Context, req *computepb.WaitGlobalOperationRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/operations/%v/wait", req.GetProject(), req.GetOperation()) @@ -414,5 +485,109 @@ func (c *globalOperationsRESTClient) Wait(ctx context.Context, req *computepb.Wa unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// OperationIterator manages a stream of *computepb.Operation. +type OperationIterator struct { + items []*computepb.Operation + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Operation, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *OperationIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *OperationIterator) Next() (*computepb.Operation, error) { + var item *computepb.Operation + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *OperationIterator) bufLen() int { + return len(it.items) +} + +func (it *OperationIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// OperationsScopedListPair is a holder type for string/*computepb.OperationsScopedList map entries +type OperationsScopedListPair struct { + Key string + Value *computepb.OperationsScopedList +} + +// OperationsScopedListPairIterator manages a stream of OperationsScopedListPair. +type OperationsScopedListPairIterator struct { + items []OperationsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []OperationsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *OperationsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *OperationsScopedListPairIterator) Next() (OperationsScopedListPair, error) { + var item OperationsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *OperationsScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *OperationsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/global_operations_client_example_test.go b/compute/apiv1/global_operations_client_example_test.go index 4cb6a7867b3..804455defda 100644 --- a/compute/apiv1/global_operations_client_example_test.go +++ b/compute/apiv1/global_operations_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleGlobalOperationsClient_AggregatedList() { req := &computepb.AggregatedListGlobalOperationsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleGlobalOperationsClient_Delete() { @@ -103,12 +110,18 @@ func ExampleGlobalOperationsClient_List() { req := &computepb.ListGlobalOperationsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleGlobalOperationsClient_Wait() { diff --git a/compute/apiv1/global_organization_operations_client.go b/compute/apiv1/global_organization_operations_client.go index 78565ecdd8d..44ce0232ef6 100644 --- a/compute/apiv1/global_organization_operations_client.go +++ b/compute/apiv1/global_organization_operations_client.go @@ -20,10 +20,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +33,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newGlobalOrganizationOperationsClientHook clientHook @@ -48,8 +51,8 @@ type internalGlobalOrganizationOperationsClient interface { setGoogleClientInfo(...string) Connection() *grpc.ClientConn Delete(context.Context, *computepb.DeleteGlobalOrganizationOperationRequest, ...gax.CallOption) (*computepb.DeleteGlobalOrganizationOperationResponse, error) - Get(context.Context, *computepb.GetGlobalOrganizationOperationRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListGlobalOrganizationOperationsRequest, ...gax.CallOption) (*computepb.OperationList, error) + Get(context.Context, *computepb.GetGlobalOrganizationOperationRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListGlobalOrganizationOperationsRequest, ...gax.CallOption) *OperationIterator } // GlobalOrganizationOperationsClient is a client for interacting with Google Compute Engine API. @@ -92,12 +95,12 @@ func (c *GlobalOrganizationOperationsClient) Delete(ctx context.Context, req *co } // Get retrieves the specified Operations resource. Gets a list of operations by making a list() request. -func (c *GlobalOrganizationOperationsClient) Get(ctx context.Context, req *computepb.GetGlobalOrganizationOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalOrganizationOperationsClient) Get(ctx context.Context, req *computepb.GetGlobalOrganizationOperationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Get(ctx, req, opts...) } // List retrieves a list of Operation resources contained within the specified organization. -func (c *GlobalOrganizationOperationsClient) List(ctx context.Context, req *computepb.ListGlobalOrganizationOperationsRequest, opts ...gax.CallOption) (*computepb.OperationList, error) { +func (c *GlobalOrganizationOperationsClient) List(ctx context.Context, req *computepb.ListGlobalOrganizationOperationsRequest, opts ...gax.CallOption) *OperationIterator { return c.internalClient.List(ctx, req, opts...) } @@ -210,7 +213,7 @@ func (c *globalOrganizationOperationsRESTClient) Delete(ctx context.Context, req } // Get retrieves the specified Operations resource. Gets a list of operations by making a list() request. -func (c *globalOrganizationOperationsRESTClient) Get(ctx context.Context, req *computepb.GetGlobalOrganizationOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalOrganizationOperationsRESTClient) Get(ctx context.Context, req *computepb.GetGlobalOrganizationOperationRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/operations/%v", req.GetOperation()) @@ -250,64 +253,96 @@ func (c *globalOrganizationOperationsRESTClient) Get(ctx context.Context, req *c unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of Operation resources contained within the specified organization. -func (c *globalOrganizationOperationsRESTClient) List(ctx context.Context, req *computepb.ListGlobalOrganizationOperationsRequest, opts ...gax.CallOption) (*computepb.OperationList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/operations") - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ParentId != nil { - params.Add("parentId", fmt.Sprintf("%v", req.GetParentId())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } - defer httpRsp.Body.Close() + op := &Operation{proto: rsp} + return op, err +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +// List retrieves a list of Operation resources contained within the specified organization. +func (c *globalOrganizationOperationsRESTClient) List(ctx context.Context, req *computepb.ListGlobalOrganizationOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*computepb.ListGlobalOrganizationOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Operation, string, error) { + resp := &computepb.OperationList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/locations/global/operations") + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ParentId != nil { + params.Add("parentId", fmt.Sprintf("%v", req.GetParentId())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.OperationList{} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - return rsp, unm.Unmarshal(buf, rsp) + return it } diff --git a/compute/apiv1/global_organization_operations_client_example_test.go b/compute/apiv1/global_organization_operations_client_example_test.go index 1018ba67433..7ddb5d1c42a 100644 --- a/compute/apiv1/global_organization_operations_client_example_test.go +++ b/compute/apiv1/global_organization_operations_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -84,10 +85,16 @@ func ExampleGlobalOrganizationOperationsClient_List() { req := &computepb.ListGlobalOrganizationOperationsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/global_public_delegated_prefixes_client.go b/compute/apiv1/global_public_delegated_prefixes_client.go index 31ee879bfc2..daa46030bbb 100644 --- a/compute/apiv1/global_public_delegated_prefixes_client.go +++ b/compute/apiv1/global_public_delegated_prefixes_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newGlobalPublicDelegatedPrefixesClientHook clientHook @@ -50,11 +53,11 @@ type internalGlobalPublicDelegatedPrefixesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteGlobalPublicDelegatedPrefixeRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteGlobalPublicDelegatedPrefixeRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetGlobalPublicDelegatedPrefixeRequest, ...gax.CallOption) (*computepb.PublicDelegatedPrefix, error) - Insert(context.Context, *computepb.InsertGlobalPublicDelegatedPrefixeRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListGlobalPublicDelegatedPrefixesRequest, ...gax.CallOption) (*computepb.PublicDelegatedPrefixList, error) - Patch(context.Context, *computepb.PatchGlobalPublicDelegatedPrefixeRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertGlobalPublicDelegatedPrefixeRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListGlobalPublicDelegatedPrefixesRequest, ...gax.CallOption) *PublicDelegatedPrefixIterator + Patch(context.Context, *computepb.PatchGlobalPublicDelegatedPrefixeRequest, ...gax.CallOption) (*Operation, error) } // GlobalPublicDelegatedPrefixesClient is a client for interacting with Google Compute Engine API. @@ -92,7 +95,7 @@ func (c *GlobalPublicDelegatedPrefixesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified global PublicDelegatedPrefix. -func (c *GlobalPublicDelegatedPrefixesClient) Delete(ctx context.Context, req *computepb.DeleteGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalPublicDelegatedPrefixesClient) Delete(ctx context.Context, req *computepb.DeleteGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -102,17 +105,17 @@ func (c *GlobalPublicDelegatedPrefixesClient) Get(ctx context.Context, req *comp } // Insert creates a global PublicDelegatedPrefix in the specified project using the parameters that are included in the request. -func (c *GlobalPublicDelegatedPrefixesClient) Insert(ctx context.Context, req *computepb.InsertGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalPublicDelegatedPrefixesClient) Insert(ctx context.Context, req *computepb.InsertGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List lists the global PublicDelegatedPrefixes for a project. -func (c *GlobalPublicDelegatedPrefixesClient) List(ctx context.Context, req *computepb.ListGlobalPublicDelegatedPrefixesRequest, opts ...gax.CallOption) (*computepb.PublicDelegatedPrefixList, error) { +func (c *GlobalPublicDelegatedPrefixesClient) List(ctx context.Context, req *computepb.ListGlobalPublicDelegatedPrefixesRequest, opts ...gax.CallOption) *PublicDelegatedPrefixIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified global PublicDelegatedPrefix resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *GlobalPublicDelegatedPrefixesClient) Patch(ctx context.Context, req *computepb.PatchGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *GlobalPublicDelegatedPrefixesClient) Patch(ctx context.Context, req *computepb.PatchGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -181,7 +184,7 @@ func (c *globalPublicDelegatedPrefixesRESTClient) Connection() *grpc.ClientConn } // Delete deletes the specified global PublicDelegatedPrefix. -func (c *globalPublicDelegatedPrefixesRESTClient) Delete(ctx context.Context, req *computepb.DeleteGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalPublicDelegatedPrefixesRESTClient) Delete(ctx context.Context, req *computepb.DeleteGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/publicDelegatedPrefixes/%v", req.GetProject(), req.GetPublicDelegatedPrefix()) @@ -221,7 +224,11 @@ func (c *globalPublicDelegatedPrefixesRESTClient) Delete(ctx context.Context, re unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified global PublicDelegatedPrefix resource. @@ -262,7 +269,7 @@ func (c *globalPublicDelegatedPrefixesRESTClient) Get(ctx context.Context, req * } // Insert creates a global PublicDelegatedPrefix in the specified project using the parameters that are included in the request. -func (c *globalPublicDelegatedPrefixesRESTClient) Insert(ctx context.Context, req *computepb.InsertGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalPublicDelegatedPrefixesRESTClient) Insert(ctx context.Context, req *computepb.InsertGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetPublicDelegatedPrefixResource() jsonReq, err := m.Marshal(body) @@ -309,67 +316,99 @@ func (c *globalPublicDelegatedPrefixesRESTClient) Insert(ctx context.Context, re unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List lists the global PublicDelegatedPrefixes for a project. -func (c *globalPublicDelegatedPrefixesRESTClient) List(ctx context.Context, req *computepb.ListGlobalPublicDelegatedPrefixesRequest, opts ...gax.CallOption) (*computepb.PublicDelegatedPrefixList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/publicDelegatedPrefixes", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List lists the global PublicDelegatedPrefixes for a project. +func (c *globalPublicDelegatedPrefixesRESTClient) List(ctx context.Context, req *computepb.ListGlobalPublicDelegatedPrefixesRequest, opts ...gax.CallOption) *PublicDelegatedPrefixIterator { + it := &PublicDelegatedPrefixIterator{} + req = proto.Clone(req).(*computepb.ListGlobalPublicDelegatedPrefixesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.PublicDelegatedPrefixList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.PublicDelegatedPrefix, string, error) { + resp := &computepb.PublicDelegatedPrefixList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/publicDelegatedPrefixes", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified global PublicDelegatedPrefix resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *globalPublicDelegatedPrefixesRESTClient) Patch(ctx context.Context, req *computepb.PatchGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *globalPublicDelegatedPrefixesRESTClient) Patch(ctx context.Context, req *computepb.PatchGlobalPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetPublicDelegatedPrefixResource() jsonReq, err := m.Marshal(body) @@ -416,5 +455,56 @@ func (c *globalPublicDelegatedPrefixesRESTClient) Patch(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// PublicDelegatedPrefixIterator manages a stream of *computepb.PublicDelegatedPrefix. +type PublicDelegatedPrefixIterator struct { + items []*computepb.PublicDelegatedPrefix + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.PublicDelegatedPrefix, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *PublicDelegatedPrefixIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *PublicDelegatedPrefixIterator) Next() (*computepb.PublicDelegatedPrefix, error) { + var item *computepb.PublicDelegatedPrefix + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *PublicDelegatedPrefixIterator) bufLen() int { + return len(it.items) +} + +func (it *PublicDelegatedPrefixIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/global_public_delegated_prefixes_client_example_test.go b/compute/apiv1/global_public_delegated_prefixes_client_example_test.go index dc9f1da0034..00d86b92dcc 100644 --- a/compute/apiv1/global_public_delegated_prefixes_client_example_test.go +++ b/compute/apiv1/global_public_delegated_prefixes_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleGlobalPublicDelegatedPrefixesClient_List() { req := &computepb.ListGlobalPublicDelegatedPrefixesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleGlobalPublicDelegatedPrefixesClient_Patch() { diff --git a/compute/apiv1/health_checks_client.go b/compute/apiv1/health_checks_client.go index ddb78d3e94c..22c7bf1e050 100644 --- a/compute/apiv1/health_checks_client.go +++ b/compute/apiv1/health_checks_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newHealthChecksClientHook clientHook @@ -52,13 +56,13 @@ type internalHealthChecksClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListHealthChecksRequest, ...gax.CallOption) (*computepb.HealthChecksAggregatedList, error) - Delete(context.Context, *computepb.DeleteHealthCheckRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListHealthChecksRequest, ...gax.CallOption) *HealthChecksScopedListPairIterator + Delete(context.Context, *computepb.DeleteHealthCheckRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetHealthCheckRequest, ...gax.CallOption) (*computepb.HealthCheck, error) - Insert(context.Context, *computepb.InsertHealthCheckRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListHealthChecksRequest, ...gax.CallOption) (*computepb.HealthCheckList, error) - Patch(context.Context, *computepb.PatchHealthCheckRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateHealthCheckRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertHealthCheckRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListHealthChecksRequest, ...gax.CallOption) *HealthCheckIterator + Patch(context.Context, *computepb.PatchHealthCheckRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateHealthCheckRequest, ...gax.CallOption) (*Operation, error) } // HealthChecksClient is a client for interacting with Google Compute Engine API. @@ -96,12 +100,12 @@ func (c *HealthChecksClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all HealthCheck resources, regional and global, available to the specified project. -func (c *HealthChecksClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListHealthChecksRequest, opts ...gax.CallOption) (*computepb.HealthChecksAggregatedList, error) { +func (c *HealthChecksClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListHealthChecksRequest, opts ...gax.CallOption) *HealthChecksScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified HealthCheck resource. -func (c *HealthChecksClient) Delete(ctx context.Context, req *computepb.DeleteHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *HealthChecksClient) Delete(ctx context.Context, req *computepb.DeleteHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -111,22 +115,22 @@ func (c *HealthChecksClient) Get(ctx context.Context, req *computepb.GetHealthCh } // Insert creates a HealthCheck resource in the specified project using the data included in the request. -func (c *HealthChecksClient) Insert(ctx context.Context, req *computepb.InsertHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *HealthChecksClient) Insert(ctx context.Context, req *computepb.InsertHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of HealthCheck resources available to the specified project. -func (c *HealthChecksClient) List(ctx context.Context, req *computepb.ListHealthChecksRequest, opts ...gax.CallOption) (*computepb.HealthCheckList, error) { +func (c *HealthChecksClient) List(ctx context.Context, req *computepb.ListHealthChecksRequest, opts ...gax.CallOption) *HealthCheckIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates a HealthCheck resource in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *HealthChecksClient) Patch(ctx context.Context, req *computepb.PatchHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *HealthChecksClient) Patch(ctx context.Context, req *computepb.PatchHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // Update updates a HealthCheck resource in the specified project using the data included in the request. -func (c *HealthChecksClient) Update(ctx context.Context, req *computepb.UpdateHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *HealthChecksClient) Update(ctx context.Context, req *computepb.UpdateHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -195,66 +199,101 @@ func (c *healthChecksRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all HealthCheck resources, regional and global, available to the specified project. -func (c *healthChecksRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListHealthChecksRequest, opts ...gax.CallOption) (*computepb.HealthChecksAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/healthChecks", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *healthChecksRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListHealthChecksRequest, opts ...gax.CallOption) *HealthChecksScopedListPairIterator { + it := &HealthChecksScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListHealthChecksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.HealthChecksAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]HealthChecksScopedListPair, string, error) { + resp := &computepb.HealthChecksAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/healthChecks", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]HealthChecksScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, HealthChecksScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified HealthCheck resource. -func (c *healthChecksRESTClient) Delete(ctx context.Context, req *computepb.DeleteHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *healthChecksRESTClient) Delete(ctx context.Context, req *computepb.DeleteHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/healthChecks/%v", req.GetProject(), req.GetHealthCheck()) @@ -294,7 +333,11 @@ func (c *healthChecksRESTClient) Delete(ctx context.Context, req *computepb.Dele unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified HealthCheck resource. Gets a list of available health checks by making a list() request. @@ -335,7 +378,7 @@ func (c *healthChecksRESTClient) Get(ctx context.Context, req *computepb.GetHeal } // Insert creates a HealthCheck resource in the specified project using the data included in the request. -func (c *healthChecksRESTClient) Insert(ctx context.Context, req *computepb.InsertHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *healthChecksRESTClient) Insert(ctx context.Context, req *computepb.InsertHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetHealthCheckResource() jsonReq, err := m.Marshal(body) @@ -382,67 +425,99 @@ func (c *healthChecksRESTClient) Insert(ctx context.Context, req *computepb.Inse unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of HealthCheck resources available to the specified project. -func (c *healthChecksRESTClient) List(ctx context.Context, req *computepb.ListHealthChecksRequest, opts ...gax.CallOption) (*computepb.HealthCheckList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/healthChecks", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of HealthCheck resources available to the specified project. +func (c *healthChecksRESTClient) List(ctx context.Context, req *computepb.ListHealthChecksRequest, opts ...gax.CallOption) *HealthCheckIterator { + it := &HealthCheckIterator{} + req = proto.Clone(req).(*computepb.ListHealthChecksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.HealthCheckList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.HealthCheck, string, error) { + resp := &computepb.HealthCheckList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/healthChecks", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates a HealthCheck resource in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *healthChecksRESTClient) Patch(ctx context.Context, req *computepb.PatchHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *healthChecksRESTClient) Patch(ctx context.Context, req *computepb.PatchHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetHealthCheckResource() jsonReq, err := m.Marshal(body) @@ -489,11 +564,15 @@ func (c *healthChecksRESTClient) Patch(ctx context.Context, req *computepb.Patch unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates a HealthCheck resource in the specified project using the data included in the request. -func (c *healthChecksRESTClient) Update(ctx context.Context, req *computepb.UpdateHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *healthChecksRESTClient) Update(ctx context.Context, req *computepb.UpdateHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetHealthCheckResource() jsonReq, err := m.Marshal(body) @@ -540,5 +619,109 @@ func (c *healthChecksRESTClient) Update(ctx context.Context, req *computepb.Upda unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// HealthCheckIterator manages a stream of *computepb.HealthCheck. +type HealthCheckIterator struct { + items []*computepb.HealthCheck + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.HealthCheck, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *HealthCheckIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *HealthCheckIterator) Next() (*computepb.HealthCheck, error) { + var item *computepb.HealthCheck + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *HealthCheckIterator) bufLen() int { + return len(it.items) +} + +func (it *HealthCheckIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// HealthChecksScopedListPair is a holder type for string/*computepb.HealthChecksScopedList map entries +type HealthChecksScopedListPair struct { + Key string + Value *computepb.HealthChecksScopedList +} + +// HealthChecksScopedListPairIterator manages a stream of HealthChecksScopedListPair. +type HealthChecksScopedListPairIterator struct { + items []HealthChecksScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []HealthChecksScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *HealthChecksScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *HealthChecksScopedListPairIterator) Next() (HealthChecksScopedListPair, error) { + var item HealthChecksScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *HealthChecksScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *HealthChecksScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/health_checks_client_example_test.go b/compute/apiv1/health_checks_client_example_test.go index fe6aeb7fe68..61d01db6940 100644 --- a/compute/apiv1/health_checks_client_example_test.go +++ b/compute/apiv1/health_checks_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleHealthChecksClient_AggregatedList() { req := &computepb.AggregatedListHealthChecksRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleHealthChecksClient_Delete() { @@ -122,12 +129,18 @@ func ExampleHealthChecksClient_List() { req := &computepb.ListHealthChecksRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleHealthChecksClient_Patch() { diff --git a/compute/apiv1/images_client.go b/compute/apiv1/images_client.go index 96af3a5f654..a18a790604d 100644 --- a/compute/apiv1/images_client.go +++ b/compute/apiv1/images_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newImagesClientHook clientHook @@ -56,16 +59,16 @@ type internalImagesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteImageRequest, ...gax.CallOption) (*computepb.Operation, error) - Deprecate(context.Context, *computepb.DeprecateImageRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteImageRequest, ...gax.CallOption) (*Operation, error) + Deprecate(context.Context, *computepb.DeprecateImageRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetImageRequest, ...gax.CallOption) (*computepb.Image, error) GetFromFamily(context.Context, *computepb.GetFromFamilyImageRequest, ...gax.CallOption) (*computepb.Image, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyImageRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertImageRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListImagesRequest, ...gax.CallOption) (*computepb.ImageList, error) - Patch(context.Context, *computepb.PatchImageRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertImageRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListImagesRequest, ...gax.CallOption) *ImageIterator + Patch(context.Context, *computepb.PatchImageRequest, ...gax.CallOption) (*Operation, error) SetIamPolicy(context.Context, *computepb.SetIamPolicyImageRequest, ...gax.CallOption) (*computepb.Policy, error) - SetLabels(context.Context, *computepb.SetLabelsImageRequest, ...gax.CallOption) (*computepb.Operation, error) + SetLabels(context.Context, *computepb.SetLabelsImageRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsImageRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -104,14 +107,14 @@ func (c *ImagesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified image. -func (c *ImagesClient) Delete(ctx context.Context, req *computepb.DeleteImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ImagesClient) Delete(ctx context.Context, req *computepb.DeleteImageRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } // Deprecate sets the deprecation status of an image. // // If an empty request body is given, clears the deprecation status instead. -func (c *ImagesClient) Deprecate(ctx context.Context, req *computepb.DeprecateImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ImagesClient) Deprecate(ctx context.Context, req *computepb.DeprecateImageRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Deprecate(ctx, req, opts...) } @@ -131,17 +134,17 @@ func (c *ImagesClient) GetIamPolicy(ctx context.Context, req *computepb.GetIamPo } // Insert creates an image in the specified project using the data included in the request. -func (c *ImagesClient) Insert(ctx context.Context, req *computepb.InsertImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ImagesClient) Insert(ctx context.Context, req *computepb.InsertImageRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of custom images available to the specified project. Custom images are images you create that belong to your project. This method does not get any images that belong to other projects, including publicly-available images, like Debian 8. If you want to get a list of publicly-available images, use this method to make a request to the respective image project, such as debian-cloud or windows-cloud. -func (c *ImagesClient) List(ctx context.Context, req *computepb.ListImagesRequest, opts ...gax.CallOption) (*computepb.ImageList, error) { +func (c *ImagesClient) List(ctx context.Context, req *computepb.ListImagesRequest, opts ...gax.CallOption) *ImageIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified image with the data included in the request. Only the following fields can be modified: family, description, deprecation status. -func (c *ImagesClient) Patch(ctx context.Context, req *computepb.PatchImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ImagesClient) Patch(ctx context.Context, req *computepb.PatchImageRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -151,7 +154,7 @@ func (c *ImagesClient) SetIamPolicy(ctx context.Context, req *computepb.SetIamPo } // SetLabels sets the labels on an image. To learn more about labels, read the Labeling Resources documentation. -func (c *ImagesClient) SetLabels(ctx context.Context, req *computepb.SetLabelsImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ImagesClient) SetLabels(ctx context.Context, req *computepb.SetLabelsImageRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetLabels(ctx, req, opts...) } @@ -225,7 +228,7 @@ func (c *imagesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified image. -func (c *imagesRESTClient) Delete(ctx context.Context, req *computepb.DeleteImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *imagesRESTClient) Delete(ctx context.Context, req *computepb.DeleteImageRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/images/%v", req.GetProject(), req.GetImage()) @@ -265,13 +268,17 @@ func (c *imagesRESTClient) Delete(ctx context.Context, req *computepb.DeleteImag unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Deprecate sets the deprecation status of an image. // // If an empty request body is given, clears the deprecation status instead. -func (c *imagesRESTClient) Deprecate(ctx context.Context, req *computepb.DeprecateImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *imagesRESTClient) Deprecate(ctx context.Context, req *computepb.DeprecateImageRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetDeprecationStatusResource() jsonReq, err := m.Marshal(body) @@ -318,7 +325,11 @@ func (c *imagesRESTClient) Deprecate(ctx context.Context, req *computepb.Depreca unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified image. Gets a list of available images by making a list() request. @@ -440,7 +451,7 @@ func (c *imagesRESTClient) GetIamPolicy(ctx context.Context, req *computepb.GetI } // Insert creates an image in the specified project using the data included in the request. -func (c *imagesRESTClient) Insert(ctx context.Context, req *computepb.InsertImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *imagesRESTClient) Insert(ctx context.Context, req *computepb.InsertImageRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetImageResource() jsonReq, err := m.Marshal(body) @@ -490,67 +501,99 @@ func (c *imagesRESTClient) Insert(ctx context.Context, req *computepb.InsertImag unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of custom images available to the specified project. Custom images are images you create that belong to your project. This method does not get any images that belong to other projects, including publicly-available images, like Debian 8. If you want to get a list of publicly-available images, use this method to make a request to the respective image project, such as debian-cloud or windows-cloud. -func (c *imagesRESTClient) List(ctx context.Context, req *computepb.ListImagesRequest, opts ...gax.CallOption) (*computepb.ImageList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/images", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of custom images available to the specified project. Custom images are images you create that belong to your project. This method does not get any images that belong to other projects, including publicly-available images, like Debian 8. If you want to get a list of publicly-available images, use this method to make a request to the respective image project, such as debian-cloud or windows-cloud. +func (c *imagesRESTClient) List(ctx context.Context, req *computepb.ListImagesRequest, opts ...gax.CallOption) *ImageIterator { + it := &ImageIterator{} + req = proto.Clone(req).(*computepb.ListImagesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ImageList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Image, string, error) { + resp := &computepb.ImageList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/images", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified image with the data included in the request. Only the following fields can be modified: family, description, deprecation status. -func (c *imagesRESTClient) Patch(ctx context.Context, req *computepb.PatchImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *imagesRESTClient) Patch(ctx context.Context, req *computepb.PatchImageRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetImageResource() jsonReq, err := m.Marshal(body) @@ -597,7 +640,11 @@ func (c *imagesRESTClient) Patch(ctx context.Context, req *computepb.PatchImageR unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -645,7 +692,7 @@ func (c *imagesRESTClient) SetIamPolicy(ctx context.Context, req *computepb.SetI } // SetLabels sets the labels on an image. To learn more about labels, read the Labeling Resources documentation. -func (c *imagesRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsImageRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *imagesRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsImageRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetGlobalSetLabelsRequestResource() jsonReq, err := m.Marshal(body) @@ -685,7 +732,11 @@ func (c *imagesRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabe unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -731,3 +782,50 @@ func (c *imagesRESTClient) TestIamPermissions(ctx context.Context, req *computep return rsp, unm.Unmarshal(buf, rsp) } + +// ImageIterator manages a stream of *computepb.Image. +type ImageIterator struct { + items []*computepb.Image + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Image, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ImageIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ImageIterator) Next() (*computepb.Image, error) { + var item *computepb.Image + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ImageIterator) bufLen() int { + return len(it.items) +} + +func (it *ImageIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/images_client_example_test.go b/compute/apiv1/images_client_example_test.go index 30c38152544..79266093111 100644 --- a/compute/apiv1/images_client_example_test.go +++ b/compute/apiv1/images_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -160,12 +161,18 @@ func ExampleImagesClient_List() { req := &computepb.ListImagesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleImagesClient_Patch() { diff --git a/compute/apiv1/instance_group_managers_client.go b/compute/apiv1/instance_group_managers_client.go index 1a4b4eb0f40..ebafbceda12 100644 --- a/compute/apiv1/instance_group_managers_client.go +++ b/compute/apiv1/instance_group_managers_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newInstanceGroupManagersClientHook clientHook @@ -65,26 +69,26 @@ type internalInstanceGroupManagersClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AbandonInstances(context.Context, *computepb.AbandonInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - AggregatedList(context.Context, *computepb.AggregatedListInstanceGroupManagersRequest, ...gax.CallOption) (*computepb.InstanceGroupManagerAggregatedList, error) - ApplyUpdatesToInstances(context.Context, *computepb.ApplyUpdatesToInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - CreateInstances(context.Context, *computepb.CreateInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - DeleteInstances(context.Context, *computepb.DeleteInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - DeletePerInstanceConfigs(context.Context, *computepb.DeletePerInstanceConfigsInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) + AbandonInstances(context.Context, *computepb.AbandonInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListInstanceGroupManagersRequest, ...gax.CallOption) *InstanceGroupManagersScopedListPairIterator + ApplyUpdatesToInstances(context.Context, *computepb.ApplyUpdatesToInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + CreateInstances(context.Context, *computepb.CreateInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + DeleteInstances(context.Context, *computepb.DeleteInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + DeletePerInstanceConfigs(context.Context, *computepb.DeletePerInstanceConfigsInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.InstanceGroupManager, error) - Insert(context.Context, *computepb.InsertInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListInstanceGroupManagersRequest, ...gax.CallOption) (*computepb.InstanceGroupManagerList, error) - ListErrors(context.Context, *computepb.ListErrorsInstanceGroupManagersRequest, ...gax.CallOption) (*computepb.InstanceGroupManagersListErrorsResponse, error) - ListManagedInstances(context.Context, *computepb.ListManagedInstancesInstanceGroupManagersRequest, ...gax.CallOption) (*computepb.InstanceGroupManagersListManagedInstancesResponse, error) - ListPerInstanceConfigs(context.Context, *computepb.ListPerInstanceConfigsInstanceGroupManagersRequest, ...gax.CallOption) (*computepb.InstanceGroupManagersListPerInstanceConfigsResp, error) - Patch(context.Context, *computepb.PatchInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - PatchPerInstanceConfigs(context.Context, *computepb.PatchPerInstanceConfigsInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - RecreateInstances(context.Context, *computepb.RecreateInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - Resize(context.Context, *computepb.ResizeInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - SetInstanceTemplate(context.Context, *computepb.SetInstanceTemplateInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - SetTargetPools(context.Context, *computepb.SetTargetPoolsInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - UpdatePerInstanceConfigs(context.Context, *computepb.UpdatePerInstanceConfigsInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListInstanceGroupManagersRequest, ...gax.CallOption) *InstanceGroupManagerIterator + ListErrors(context.Context, *computepb.ListErrorsInstanceGroupManagersRequest, ...gax.CallOption) *InstanceManagedByIgmErrorIterator + ListManagedInstances(context.Context, *computepb.ListManagedInstancesInstanceGroupManagersRequest, ...gax.CallOption) *ManagedInstanceIterator + ListPerInstanceConfigs(context.Context, *computepb.ListPerInstanceConfigsInstanceGroupManagersRequest, ...gax.CallOption) *PerInstanceConfigIterator + Patch(context.Context, *computepb.PatchInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + PatchPerInstanceConfigs(context.Context, *computepb.PatchPerInstanceConfigsInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + RecreateInstances(context.Context, *computepb.RecreateInstancesInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + Resize(context.Context, *computepb.ResizeInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + SetInstanceTemplate(context.Context, *computepb.SetInstanceTemplateInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + SetTargetPools(context.Context, *computepb.SetTargetPoolsInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + UpdatePerInstanceConfigs(context.Context, *computepb.UpdatePerInstanceConfigsInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) } // InstanceGroupManagersClient is a client for interacting with Google Compute Engine API. @@ -126,27 +130,27 @@ func (c *InstanceGroupManagersClient) Connection() *grpc.ClientConn { // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *InstanceGroupManagersClient) AbandonInstances(ctx context.Context, req *computepb.AbandonInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) AbandonInstances(ctx context.Context, req *computepb.AbandonInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AbandonInstances(ctx, req, opts...) } // AggregatedList retrieves the list of managed instance groups and groups them by zone. -func (c *InstanceGroupManagersClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagerAggregatedList, error) { +func (c *InstanceGroupManagersClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceGroupManagersScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // ApplyUpdatesToInstances applies changes to selected instances on the managed instance group. This method can be used to apply new overrides and/or new versions. -func (c *InstanceGroupManagersClient) ApplyUpdatesToInstances(ctx context.Context, req *computepb.ApplyUpdatesToInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) ApplyUpdatesToInstances(ctx context.Context, req *computepb.ApplyUpdatesToInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.ApplyUpdatesToInstances(ctx, req, opts...) } // CreateInstances creates instances with per-instance configs in this managed instance group. Instances are created using the current instance template. The create instances operation is marked DONE if the createInstances request is successful. The underlying actions take additional time. You must separately verify the status of the creating or actions with the listmanagedinstances method. -func (c *InstanceGroupManagersClient) CreateInstances(ctx context.Context, req *computepb.CreateInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) CreateInstances(ctx context.Context, req *computepb.CreateInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.CreateInstances(ctx, req, opts...) } // Delete deletes the specified managed instance group and all of the instances in that group. Note that the instance group must not belong to a backend service. Read Deleting an instance group for more information. -func (c *InstanceGroupManagersClient) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -155,12 +159,12 @@ func (c *InstanceGroupManagersClient) Delete(ctx context.Context, req *computepb // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *InstanceGroupManagersClient) DeleteInstances(ctx context.Context, req *computepb.DeleteInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) DeleteInstances(ctx context.Context, req *computepb.DeleteInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DeleteInstances(ctx, req, opts...) } // DeletePerInstanceConfigs deletes selected per-instance configs for the managed instance group. -func (c *InstanceGroupManagersClient) DeletePerInstanceConfigs(ctx context.Context, req *computepb.DeletePerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) DeletePerInstanceConfigs(ctx context.Context, req *computepb.DeletePerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DeletePerInstanceConfigs(ctx, req, opts...) } @@ -172,37 +176,37 @@ func (c *InstanceGroupManagersClient) Get(ctx context.Context, req *computepb.Ge // Insert creates a managed instance group using the information that you specify in the request. After the group is created, instances in the group are created using the specified instance template. This operation is marked as DONE when the group is created even if the instances in the group have not yet been created. You must separately verify the status of the individual instances with the listmanagedinstances method. // // A managed instance group can have up to 1000 VM instances per group. Please contact Cloud Support if you need an increase in this limit. -func (c *InstanceGroupManagersClient) Insert(ctx context.Context, req *computepb.InsertInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) Insert(ctx context.Context, req *computepb.InsertInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of managed instance groups that are contained within the specified project and zone. -func (c *InstanceGroupManagersClient) List(ctx context.Context, req *computepb.ListInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagerList, error) { +func (c *InstanceGroupManagersClient) List(ctx context.Context, req *computepb.ListInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceGroupManagerIterator { return c.internalClient.List(ctx, req, opts...) } // ListErrors lists all errors thrown by actions on instances for a given managed instance group. The filter and orderBy query parameters are not supported. -func (c *InstanceGroupManagersClient) ListErrors(ctx context.Context, req *computepb.ListErrorsInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagersListErrorsResponse, error) { +func (c *InstanceGroupManagersClient) ListErrors(ctx context.Context, req *computepb.ListErrorsInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceManagedByIgmErrorIterator { return c.internalClient.ListErrors(ctx, req, opts...) } // ListManagedInstances lists all of the instances in the managed instance group. Each instance in the list has a currentAction, which indicates the action that the managed instance group is performing on the instance. For example, if the group is still creating an instance, the currentAction is CREATING. If a previous action failed, the list displays the errors for that failed action. The orderBy query parameter is not supported. -func (c *InstanceGroupManagersClient) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagersListManagedInstancesResponse, error) { +func (c *InstanceGroupManagersClient) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesInstanceGroupManagersRequest, opts ...gax.CallOption) *ManagedInstanceIterator { return c.internalClient.ListManagedInstances(ctx, req, opts...) } // ListPerInstanceConfigs lists all of the per-instance configs defined for the managed instance group. The orderBy query parameter is not supported. -func (c *InstanceGroupManagersClient) ListPerInstanceConfigs(ctx context.Context, req *computepb.ListPerInstanceConfigsInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagersListPerInstanceConfigsResp, error) { +func (c *InstanceGroupManagersClient) ListPerInstanceConfigs(ctx context.Context, req *computepb.ListPerInstanceConfigsInstanceGroupManagersRequest, opts ...gax.CallOption) *PerInstanceConfigIterator { return c.internalClient.ListPerInstanceConfigs(ctx, req, opts...) } // Patch updates a managed instance group using the information that you specify in the request. This operation is marked as DONE when the group is patched even if the instances in the group are still in the process of being patched. You must separately verify the status of the individual instances with the listManagedInstances method. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *InstanceGroupManagersClient) Patch(ctx context.Context, req *computepb.PatchInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) Patch(ctx context.Context, req *computepb.PatchInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // PatchPerInstanceConfigs inserts or patches per-instance configs for the managed instance group. perInstanceConfig.name (at http://perInstanceConfig.name) serves as a key used to distinguish whether to perform insert or patch. -func (c *InstanceGroupManagersClient) PatchPerInstanceConfigs(ctx context.Context, req *computepb.PatchPerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) PatchPerInstanceConfigs(ctx context.Context, req *computepb.PatchPerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.PatchPerInstanceConfigs(ctx, req, opts...) } @@ -211,7 +215,7 @@ func (c *InstanceGroupManagersClient) PatchPerInstanceConfigs(ctx context.Contex // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *InstanceGroupManagersClient) RecreateInstances(ctx context.Context, req *computepb.RecreateInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) RecreateInstances(ctx context.Context, req *computepb.RecreateInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RecreateInstances(ctx, req, opts...) } @@ -224,22 +228,22 @@ func (c *InstanceGroupManagersClient) RecreateInstances(ctx context.Context, req // This list is subject to change. // // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. -func (c *InstanceGroupManagersClient) Resize(ctx context.Context, req *computepb.ResizeInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) Resize(ctx context.Context, req *computepb.ResizeInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Resize(ctx, req, opts...) } // SetInstanceTemplate specifies the instance template to use when creating new instances in this group. The templates for existing instances in the group do not change unless you run recreateInstances, run applyUpdatesToInstances, or set the group’s updatePolicy.type to PROACTIVE. -func (c *InstanceGroupManagersClient) SetInstanceTemplate(ctx context.Context, req *computepb.SetInstanceTemplateInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) SetInstanceTemplate(ctx context.Context, req *computepb.SetInstanceTemplateInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetInstanceTemplate(ctx, req, opts...) } // SetTargetPools modifies the target pools to which all instances in this managed instance group are assigned. The target pools automatically apply to all of the instances in the managed instance group. This operation is marked DONE when you make the request even if the instances have not yet been added to their target pools. The change might take some time to apply to all of the instances in the group depending on the size of the group. -func (c *InstanceGroupManagersClient) SetTargetPools(ctx context.Context, req *computepb.SetTargetPoolsInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) SetTargetPools(ctx context.Context, req *computepb.SetTargetPoolsInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetTargetPools(ctx, req, opts...) } // UpdatePerInstanceConfigs inserts or updates per-instance configs for the managed instance group. perInstanceConfig.name (at http://perInstanceConfig.name) serves as a key used to distinguish whether to perform insert or patch. -func (c *InstanceGroupManagersClient) UpdatePerInstanceConfigs(ctx context.Context, req *computepb.UpdatePerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupManagersClient) UpdatePerInstanceConfigs(ctx context.Context, req *computepb.UpdatePerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.UpdatePerInstanceConfigs(ctx, req, opts...) } @@ -312,7 +316,7 @@ func (c *instanceGroupManagersRESTClient) Connection() *grpc.ClientConn { // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *instanceGroupManagersRESTClient) AbandonInstances(ctx context.Context, req *computepb.AbandonInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) AbandonInstances(ctx context.Context, req *computepb.AbandonInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersAbandonInstancesRequestResource() jsonReq, err := m.Marshal(body) @@ -359,70 +363,109 @@ func (c *instanceGroupManagersRESTClient) AbandonInstances(ctx context.Context, unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// AggregatedList retrieves the list of managed instance groups and groups them by zone. -func (c *instanceGroupManagersRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagerAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/instanceGroupManagers", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// AggregatedList retrieves the list of managed instance groups and groups them by zone. +func (c *instanceGroupManagersRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceGroupManagersScopedListPairIterator { + it := &InstanceGroupManagersScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListInstanceGroupManagersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceGroupManagerAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]InstanceGroupManagersScopedListPair, string, error) { + resp := &computepb.InstanceGroupManagerAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/instanceGroupManagers", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]InstanceGroupManagersScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, InstanceGroupManagersScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ApplyUpdatesToInstances applies changes to selected instances on the managed instance group. This method can be used to apply new overrides and/or new versions. -func (c *instanceGroupManagersRESTClient) ApplyUpdatesToInstances(ctx context.Context, req *computepb.ApplyUpdatesToInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) ApplyUpdatesToInstances(ctx context.Context, req *computepb.ApplyUpdatesToInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersApplyUpdatesRequestResource() jsonReq, err := m.Marshal(body) @@ -462,11 +505,15 @@ func (c *instanceGroupManagersRESTClient) ApplyUpdatesToInstances(ctx context.Co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // CreateInstances creates instances with per-instance configs in this managed instance group. Instances are created using the current instance template. The create instances operation is marked DONE if the createInstances request is successful. The underlying actions take additional time. You must separately verify the status of the creating or actions with the listmanagedinstances method. -func (c *instanceGroupManagersRESTClient) CreateInstances(ctx context.Context, req *computepb.CreateInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) CreateInstances(ctx context.Context, req *computepb.CreateInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersCreateInstancesRequestResource() jsonReq, err := m.Marshal(body) @@ -513,11 +560,15 @@ func (c *instanceGroupManagersRESTClient) CreateInstances(ctx context.Context, r unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified managed instance group and all of the instances in that group. Note that the instance group must not belong to a backend service. Read Deleting an instance group for more information. -func (c *instanceGroupManagersRESTClient) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers/%v", req.GetProject(), req.GetZone(), req.GetInstanceGroupManager()) @@ -557,7 +608,11 @@ func (c *instanceGroupManagersRESTClient) Delete(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DeleteInstances flags the specified instances in the managed instance group for immediate deletion. The instances are also removed from any target pools of which they were a member. This method reduces the targetSize of the managed instance group by the number of instances that you delete. This operation is marked as DONE when the action is scheduled even if the instances are still being deleted. You must separately verify the status of the deleting action with the listmanagedinstances method. @@ -565,7 +620,7 @@ func (c *instanceGroupManagersRESTClient) Delete(ctx context.Context, req *compu // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *instanceGroupManagersRESTClient) DeleteInstances(ctx context.Context, req *computepb.DeleteInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) DeleteInstances(ctx context.Context, req *computepb.DeleteInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersDeleteInstancesRequestResource() jsonReq, err := m.Marshal(body) @@ -612,11 +667,15 @@ func (c *instanceGroupManagersRESTClient) DeleteInstances(ctx context.Context, r unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DeletePerInstanceConfigs deletes selected per-instance configs for the managed instance group. -func (c *instanceGroupManagersRESTClient) DeletePerInstanceConfigs(ctx context.Context, req *computepb.DeletePerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) DeletePerInstanceConfigs(ctx context.Context, req *computepb.DeletePerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersDeletePerInstanceConfigsReqResource() jsonReq, err := m.Marshal(body) @@ -656,7 +715,11 @@ func (c *instanceGroupManagersRESTClient) DeletePerInstanceConfigs(ctx context.C unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns all of the details about the specified managed instance group. Gets a list of available managed instance groups by making a list() request. @@ -699,7 +762,7 @@ func (c *instanceGroupManagersRESTClient) Get(ctx context.Context, req *computep // Insert creates a managed instance group using the information that you specify in the request. After the group is created, instances in the group are created using the specified instance template. This operation is marked as DONE when the group is created even if the instances in the group have not yet been created. You must separately verify the status of the individual instances with the listmanagedinstances method. // // A managed instance group can have up to 1000 VM instances per group. Please contact Cloud Support if you need an increase in this limit. -func (c *instanceGroupManagersRESTClient) Insert(ctx context.Context, req *computepb.InsertInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) Insert(ctx context.Context, req *computepb.InsertInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagerResource() jsonReq, err := m.Marshal(body) @@ -746,235 +809,351 @@ func (c *instanceGroupManagersRESTClient) Insert(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of managed instance groups that are contained within the specified project and zone. -func (c *instanceGroupManagersRESTClient) List(ctx context.Context, req *computepb.ListInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagerList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of managed instance groups that are contained within the specified project and zone. +func (c *instanceGroupManagersRESTClient) List(ctx context.Context, req *computepb.ListInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceGroupManagerIterator { + it := &InstanceGroupManagerIterator{} + req = proto.Clone(req).(*computepb.ListInstanceGroupManagersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceGroupManagerList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InstanceGroupManager, string, error) { + resp := &computepb.InstanceGroupManagerList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListErrors lists all errors thrown by actions on instances for a given managed instance group. The filter and orderBy query parameters are not supported. -func (c *instanceGroupManagersRESTClient) ListErrors(ctx context.Context, req *computepb.ListErrorsInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagersListErrorsResponse, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers/%v/listErrors", req.GetProject(), req.GetZone(), req.GetInstanceGroupManager()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *instanceGroupManagersRESTClient) ListErrors(ctx context.Context, req *computepb.ListErrorsInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceManagedByIgmErrorIterator { + it := &InstanceManagedByIgmErrorIterator{} + req = proto.Clone(req).(*computepb.ListErrorsInstanceGroupManagersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceGroupManagersListErrorsResponse{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InstanceManagedByIgmError, string, error) { + resp := &computepb.InstanceGroupManagersListErrorsResponse{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers/%v/listErrors", req.GetProject(), req.GetZone(), req.GetInstanceGroupManager()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListManagedInstances lists all of the instances in the managed instance group. Each instance in the list has a currentAction, which indicates the action that the managed instance group is performing on the instance. For example, if the group is still creating an instance, the currentAction is CREATING. If a previous action failed, the list displays the errors for that failed action. The orderBy query parameter is not supported. -func (c *instanceGroupManagersRESTClient) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagersListManagedInstancesResponse, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers/%v/listManagedInstances", req.GetProject(), req.GetZone(), req.GetInstanceGroupManager()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *instanceGroupManagersRESTClient) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesInstanceGroupManagersRequest, opts ...gax.CallOption) *ManagedInstanceIterator { + it := &ManagedInstanceIterator{} + req = proto.Clone(req).(*computepb.ListManagedInstancesInstanceGroupManagersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceGroupManagersListManagedInstancesResponse{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.ManagedInstance, string, error) { + resp := &computepb.InstanceGroupManagersListManagedInstancesResponse{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers/%v/listManagedInstances", req.GetProject(), req.GetZone(), req.GetInstanceGroupManager()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetManagedInstances(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListPerInstanceConfigs lists all of the per-instance configs defined for the managed instance group. The orderBy query parameter is not supported. -func (c *instanceGroupManagersRESTClient) ListPerInstanceConfigs(ctx context.Context, req *computepb.ListPerInstanceConfigsInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.InstanceGroupManagersListPerInstanceConfigsResp, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers/%v/listPerInstanceConfigs", req.GetProject(), req.GetZone(), req.GetInstanceGroupManager()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *instanceGroupManagersRESTClient) ListPerInstanceConfigs(ctx context.Context, req *computepb.ListPerInstanceConfigsInstanceGroupManagersRequest, opts ...gax.CallOption) *PerInstanceConfigIterator { + it := &PerInstanceConfigIterator{} + req = proto.Clone(req).(*computepb.ListPerInstanceConfigsInstanceGroupManagersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceGroupManagersListPerInstanceConfigsResp{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.PerInstanceConfig, string, error) { + resp := &computepb.InstanceGroupManagersListPerInstanceConfigsResp{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers/%v/listPerInstanceConfigs", req.GetProject(), req.GetZone(), req.GetInstanceGroupManager()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates a managed instance group using the information that you specify in the request. This operation is marked as DONE when the group is patched even if the instances in the group are still in the process of being patched. You must separately verify the status of the individual instances with the listManagedInstances method. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *instanceGroupManagersRESTClient) Patch(ctx context.Context, req *computepb.PatchInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) Patch(ctx context.Context, req *computepb.PatchInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagerResource() jsonReq, err := m.Marshal(body) @@ -1021,11 +1200,15 @@ func (c *instanceGroupManagersRESTClient) Patch(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // PatchPerInstanceConfigs inserts or patches per-instance configs for the managed instance group. perInstanceConfig.name (at http://perInstanceConfig.name) serves as a key used to distinguish whether to perform insert or patch. -func (c *instanceGroupManagersRESTClient) PatchPerInstanceConfigs(ctx context.Context, req *computepb.PatchPerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) PatchPerInstanceConfigs(ctx context.Context, req *computepb.PatchPerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersPatchPerInstanceConfigsReqResource() jsonReq, err := m.Marshal(body) @@ -1072,7 +1255,11 @@ func (c *instanceGroupManagersRESTClient) PatchPerInstanceConfigs(ctx context.Co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // RecreateInstances flags the specified VM instances in the managed instance group to be immediately recreated. Each instance is recreated using the group’s current configuration. This operation is marked as DONE when the flag is set even if the instances have not yet been recreated. You must separately verify the status of each instance by checking its currentAction field; for more information, see Checking the status of managed instances. @@ -1080,7 +1267,7 @@ func (c *instanceGroupManagersRESTClient) PatchPerInstanceConfigs(ctx context.Co // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *instanceGroupManagersRESTClient) RecreateInstances(ctx context.Context, req *computepb.RecreateInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) RecreateInstances(ctx context.Context, req *computepb.RecreateInstancesInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersRecreateInstancesRequestResource() jsonReq, err := m.Marshal(body) @@ -1127,7 +1314,11 @@ func (c *instanceGroupManagersRESTClient) RecreateInstances(ctx context.Context, unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Resize resizes the managed instance group. If you increase the size, the group creates new instances using the current instance template. If you decrease the size, the group deletes instances. The resize operation is marked DONE when the resize actions are scheduled even if the group has not yet added or deleted any instances. You must separately verify the status of the creating or deleting actions with the listmanagedinstances method. @@ -1139,7 +1330,7 @@ func (c *instanceGroupManagersRESTClient) RecreateInstances(ctx context.Context, // This list is subject to change. // // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. -func (c *instanceGroupManagersRESTClient) Resize(ctx context.Context, req *computepb.ResizeInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) Resize(ctx context.Context, req *computepb.ResizeInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroupManagers/%v/resize", req.GetProject(), req.GetZone(), req.GetInstanceGroupManager()) @@ -1182,11 +1373,15 @@ func (c *instanceGroupManagersRESTClient) Resize(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetInstanceTemplate specifies the instance template to use when creating new instances in this group. The templates for existing instances in the group do not change unless you run recreateInstances, run applyUpdatesToInstances, or set the group’s updatePolicy.type to PROACTIVE. -func (c *instanceGroupManagersRESTClient) SetInstanceTemplate(ctx context.Context, req *computepb.SetInstanceTemplateInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) SetInstanceTemplate(ctx context.Context, req *computepb.SetInstanceTemplateInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersSetInstanceTemplateRequestResource() jsonReq, err := m.Marshal(body) @@ -1233,11 +1428,15 @@ func (c *instanceGroupManagersRESTClient) SetInstanceTemplate(ctx context.Contex unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetTargetPools modifies the target pools to which all instances in this managed instance group are assigned. The target pools automatically apply to all of the instances in the managed instance group. This operation is marked DONE when you make the request even if the instances have not yet been added to their target pools. The change might take some time to apply to all of the instances in the group depending on the size of the group. -func (c *instanceGroupManagersRESTClient) SetTargetPools(ctx context.Context, req *computepb.SetTargetPoolsInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) SetTargetPools(ctx context.Context, req *computepb.SetTargetPoolsInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersSetTargetPoolsRequestResource() jsonReq, err := m.Marshal(body) @@ -1284,11 +1483,15 @@ func (c *instanceGroupManagersRESTClient) SetTargetPools(ctx context.Context, re unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // UpdatePerInstanceConfigs inserts or updates per-instance configs for the managed instance group. perInstanceConfig.name (at http://perInstanceConfig.name) serves as a key used to distinguish whether to perform insert or patch. -func (c *instanceGroupManagersRESTClient) UpdatePerInstanceConfigs(ctx context.Context, req *computepb.UpdatePerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupManagersRESTClient) UpdatePerInstanceConfigs(ctx context.Context, req *computepb.UpdatePerInstanceConfigsInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagersUpdatePerInstanceConfigsReqResource() jsonReq, err := m.Marshal(body) @@ -1335,5 +1538,250 @@ func (c *instanceGroupManagersRESTClient) UpdatePerInstanceConfigs(ctx context.C unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// InstanceGroupManagerIterator manages a stream of *computepb.InstanceGroupManager. +type InstanceGroupManagerIterator struct { + items []*computepb.InstanceGroupManager + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.InstanceGroupManager, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceGroupManagerIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceGroupManagerIterator) Next() (*computepb.InstanceGroupManager, error) { + var item *computepb.InstanceGroupManager + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceGroupManagerIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceGroupManagerIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InstanceGroupManagersScopedListPair is a holder type for string/*computepb.InstanceGroupManagersScopedList map entries +type InstanceGroupManagersScopedListPair struct { + Key string + Value *computepb.InstanceGroupManagersScopedList +} + +// InstanceGroupManagersScopedListPairIterator manages a stream of InstanceGroupManagersScopedListPair. +type InstanceGroupManagersScopedListPairIterator struct { + items []InstanceGroupManagersScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []InstanceGroupManagersScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceGroupManagersScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceGroupManagersScopedListPairIterator) Next() (InstanceGroupManagersScopedListPair, error) { + var item InstanceGroupManagersScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceGroupManagersScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceGroupManagersScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InstanceManagedByIgmErrorIterator manages a stream of *computepb.InstanceManagedByIgmError. +type InstanceManagedByIgmErrorIterator struct { + items []*computepb.InstanceManagedByIgmError + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.InstanceManagedByIgmError, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceManagedByIgmErrorIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceManagedByIgmErrorIterator) Next() (*computepb.InstanceManagedByIgmError, error) { + var item *computepb.InstanceManagedByIgmError + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceManagedByIgmErrorIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceManagedByIgmErrorIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ManagedInstanceIterator manages a stream of *computepb.ManagedInstance. +type ManagedInstanceIterator struct { + items []*computepb.ManagedInstance + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.ManagedInstance, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ManagedInstanceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ManagedInstanceIterator) Next() (*computepb.ManagedInstance, error) { + var item *computepb.ManagedInstance + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ManagedInstanceIterator) bufLen() int { + return len(it.items) +} + +func (it *ManagedInstanceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// PerInstanceConfigIterator manages a stream of *computepb.PerInstanceConfig. +type PerInstanceConfigIterator struct { + items []*computepb.PerInstanceConfig + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.PerInstanceConfig, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *PerInstanceConfigIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *PerInstanceConfigIterator) Next() (*computepb.PerInstanceConfig, error) { + var item *computepb.PerInstanceConfig + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *PerInstanceConfigIterator) bufLen() int { + return len(it.items) +} + +func (it *PerInstanceConfigIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/instance_group_managers_client_example_test.go b/compute/apiv1/instance_group_managers_client_example_test.go index d5602e70117..dbab0b526fc 100644 --- a/compute/apiv1/instance_group_managers_client_example_test.go +++ b/compute/apiv1/instance_group_managers_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,12 +66,18 @@ func ExampleInstanceGroupManagersClient_AggregatedList() { req := &computepb.AggregatedListInstanceGroupManagersRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstanceGroupManagersClient_ApplyUpdatesToInstances() { @@ -217,12 +224,18 @@ func ExampleInstanceGroupManagersClient_List() { req := &computepb.ListInstanceGroupManagersRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstanceGroupManagersClient_ListErrors() { @@ -236,12 +249,18 @@ func ExampleInstanceGroupManagersClient_ListErrors() { req := &computepb.ListErrorsInstanceGroupManagersRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListErrors(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListErrors(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstanceGroupManagersClient_ListManagedInstances() { @@ -255,12 +274,18 @@ func ExampleInstanceGroupManagersClient_ListManagedInstances() { req := &computepb.ListManagedInstancesInstanceGroupManagersRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListManagedInstances(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListManagedInstances(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstanceGroupManagersClient_ListPerInstanceConfigs() { @@ -274,12 +299,18 @@ func ExampleInstanceGroupManagersClient_ListPerInstanceConfigs() { req := &computepb.ListPerInstanceConfigsInstanceGroupManagersRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListPerInstanceConfigs(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListPerInstanceConfigs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstanceGroupManagersClient_Patch() { diff --git a/compute/apiv1/instance_groups_client.go b/compute/apiv1/instance_groups_client.go index 06820b63577..817cfc69229 100644 --- a/compute/apiv1/instance_groups_client.go +++ b/compute/apiv1/instance_groups_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newInstanceGroupsClientHook clientHook @@ -54,15 +58,15 @@ type internalInstanceGroupsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddInstances(context.Context, *computepb.AddInstancesInstanceGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - AggregatedList(context.Context, *computepb.AggregatedListInstanceGroupsRequest, ...gax.CallOption) (*computepb.InstanceGroupAggregatedList, error) - Delete(context.Context, *computepb.DeleteInstanceGroupRequest, ...gax.CallOption) (*computepb.Operation, error) + AddInstances(context.Context, *computepb.AddInstancesInstanceGroupRequest, ...gax.CallOption) (*Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListInstanceGroupsRequest, ...gax.CallOption) *InstanceGroupsScopedListPairIterator + Delete(context.Context, *computepb.DeleteInstanceGroupRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetInstanceGroupRequest, ...gax.CallOption) (*computepb.InstanceGroup, error) - Insert(context.Context, *computepb.InsertInstanceGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListInstanceGroupsRequest, ...gax.CallOption) (*computepb.InstanceGroupList, error) - ListInstances(context.Context, *computepb.ListInstancesInstanceGroupsRequest, ...gax.CallOption) (*computepb.InstanceGroupsListInstances, error) - RemoveInstances(context.Context, *computepb.RemoveInstancesInstanceGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - SetNamedPorts(context.Context, *computepb.SetNamedPortsInstanceGroupRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertInstanceGroupRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListInstanceGroupsRequest, ...gax.CallOption) *InstanceGroupIterator + ListInstances(context.Context, *computepb.ListInstancesInstanceGroupsRequest, ...gax.CallOption) *InstanceWithNamedPortsIterator + RemoveInstances(context.Context, *computepb.RemoveInstancesInstanceGroupRequest, ...gax.CallOption) (*Operation, error) + SetNamedPorts(context.Context, *computepb.SetNamedPortsInstanceGroupRequest, ...gax.CallOption) (*Operation, error) } // InstanceGroupsClient is a client for interacting with Google Compute Engine API. @@ -100,17 +104,17 @@ func (c *InstanceGroupsClient) Connection() *grpc.ClientConn { } // AddInstances adds a list of instances to the specified instance group. All of the instances in the instance group must be in the same network/subnetwork. Read Adding instances for more information. -func (c *InstanceGroupsClient) AddInstances(ctx context.Context, req *computepb.AddInstancesInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupsClient) AddInstances(ctx context.Context, req *computepb.AddInstancesInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddInstances(ctx, req, opts...) } // AggregatedList retrieves the list of instance groups and sorts them by zone. -func (c *InstanceGroupsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.InstanceGroupAggregatedList, error) { +func (c *InstanceGroupsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstanceGroupsRequest, opts ...gax.CallOption) *InstanceGroupsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified instance group. The instances in the group are not deleted. Note that instance group must not belong to a backend service. Read Deleting an instance group for more information. -func (c *InstanceGroupsClient) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupsClient) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -122,31 +126,31 @@ func (c *InstanceGroupsClient) Get(ctx context.Context, req *computepb.GetInstan } // Insert creates an instance group in the specified project using the parameters that are included in the request. -func (c *InstanceGroupsClient) Insert(ctx context.Context, req *computepb.InsertInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupsClient) Insert(ctx context.Context, req *computepb.InsertInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of zonal instance group resources contained within the specified zone. // // For managed instance groups, use the instanceGroupManagers or regionInstanceGroupManagers methods instead. -func (c *InstanceGroupsClient) List(ctx context.Context, req *computepb.ListInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.InstanceGroupList, error) { +func (c *InstanceGroupsClient) List(ctx context.Context, req *computepb.ListInstanceGroupsRequest, opts ...gax.CallOption) *InstanceGroupIterator { return c.internalClient.List(ctx, req, opts...) } // ListInstances lists the instances in the specified instance group. The orderBy query parameter is not supported. -func (c *InstanceGroupsClient) ListInstances(ctx context.Context, req *computepb.ListInstancesInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.InstanceGroupsListInstances, error) { +func (c *InstanceGroupsClient) ListInstances(ctx context.Context, req *computepb.ListInstancesInstanceGroupsRequest, opts ...gax.CallOption) *InstanceWithNamedPortsIterator { return c.internalClient.ListInstances(ctx, req, opts...) } // RemoveInstances removes one or more instances from the specified instance group, but does not delete those instances. // // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration before the VM instance is removed or deleted. -func (c *InstanceGroupsClient) RemoveInstances(ctx context.Context, req *computepb.RemoveInstancesInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupsClient) RemoveInstances(ctx context.Context, req *computepb.RemoveInstancesInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemoveInstances(ctx, req, opts...) } // SetNamedPorts sets the named ports for the specified instance group. -func (c *InstanceGroupsClient) SetNamedPorts(ctx context.Context, req *computepb.SetNamedPortsInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceGroupsClient) SetNamedPorts(ctx context.Context, req *computepb.SetNamedPortsInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetNamedPorts(ctx, req, opts...) } @@ -215,7 +219,7 @@ func (c *instanceGroupsRESTClient) Connection() *grpc.ClientConn { } // AddInstances adds a list of instances to the specified instance group. All of the instances in the instance group must be in the same network/subnetwork. Read Adding instances for more information. -func (c *instanceGroupsRESTClient) AddInstances(ctx context.Context, req *computepb.AddInstancesInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupsRESTClient) AddInstances(ctx context.Context, req *computepb.AddInstancesInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupsAddInstancesRequestResource() jsonReq, err := m.Marshal(body) @@ -262,70 +266,109 @@ func (c *instanceGroupsRESTClient) AddInstances(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// AggregatedList retrieves the list of instance groups and sorts them by zone. -func (c *instanceGroupsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.InstanceGroupAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/instanceGroups", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// AggregatedList retrieves the list of instance groups and sorts them by zone. +func (c *instanceGroupsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstanceGroupsRequest, opts ...gax.CallOption) *InstanceGroupsScopedListPairIterator { + it := &InstanceGroupsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListInstanceGroupsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceGroupAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]InstanceGroupsScopedListPair, string, error) { + resp := &computepb.InstanceGroupAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/instanceGroups", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]InstanceGroupsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, InstanceGroupsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified instance group. The instances in the group are not deleted. Note that instance group must not belong to a backend service. Read Deleting an instance group for more information. -func (c *instanceGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroups/%v", req.GetProject(), req.GetZone(), req.GetInstanceGroup()) @@ -365,7 +408,11 @@ func (c *instanceGroupsRESTClient) Delete(ctx context.Context, req *computepb.De unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified zonal instance group. Get a list of available zonal instance groups by making a list() request. @@ -408,7 +455,7 @@ func (c *instanceGroupsRESTClient) Get(ctx context.Context, req *computepb.GetIn } // Insert creates an instance group in the specified project using the parameters that are included in the request. -func (c *instanceGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupResource() jsonReq, err := m.Marshal(body) @@ -455,134 +502,193 @@ func (c *instanceGroupsRESTClient) Insert(ctx context.Context, req *computepb.In unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List retrieves the list of zonal instance group resources contained within the specified zone. // // For managed instance groups, use the instanceGroupManagers or regionInstanceGroupManagers methods instead. -func (c *instanceGroupsRESTClient) List(ctx context.Context, req *computepb.ListInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.InstanceGroupList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroups", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *instanceGroupsRESTClient) List(ctx context.Context, req *computepb.ListInstanceGroupsRequest, opts ...gax.CallOption) *InstanceGroupIterator { + it := &InstanceGroupIterator{} + req = proto.Clone(req).(*computepb.ListInstanceGroupsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceGroupList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InstanceGroup, string, error) { + resp := &computepb.InstanceGroupList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroups", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListInstances lists the instances in the specified instance group. The orderBy query parameter is not supported. -func (c *instanceGroupsRESTClient) ListInstances(ctx context.Context, req *computepb.ListInstancesInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.InstanceGroupsListInstances, error) { - m := protojson.MarshalOptions{AllowPartial: true} - body := req.GetInstanceGroupsListInstancesRequestResource() - jsonReq, err := m.Marshal(body) - if err != nil { - return nil, err - } - - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroups/%v/listInstances", req.GetProject(), req.GetZone(), req.GetInstanceGroup()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *instanceGroupsRESTClient) ListInstances(ctx context.Context, req *computepb.ListInstancesInstanceGroupsRequest, opts ...gax.CallOption) *InstanceWithNamedPortsIterator { + it := &InstanceWithNamedPortsIterator{} + req = proto.Clone(req).(*computepb.ListInstancesInstanceGroupsRequest) + m := protojson.MarshalOptions{AllowPartial: true, UseProtoNames: false} unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceGroupsListInstances{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InstanceWithNamedPorts, string, error) { + resp := &computepb.InstanceGroupsListInstances{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, "", err + } + + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instanceGroups/%v/listInstances", req.GetProject(), req.GetZone(), req.GetInstanceGroup()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // RemoveInstances removes one or more instances from the specified instance group, but does not delete those instances. // // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration before the VM instance is removed or deleted. -func (c *instanceGroupsRESTClient) RemoveInstances(ctx context.Context, req *computepb.RemoveInstancesInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupsRESTClient) RemoveInstances(ctx context.Context, req *computepb.RemoveInstancesInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupsRemoveInstancesRequestResource() jsonReq, err := m.Marshal(body) @@ -629,11 +735,15 @@ func (c *instanceGroupsRESTClient) RemoveInstances(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetNamedPorts sets the named ports for the specified instance group. -func (c *instanceGroupsRESTClient) SetNamedPorts(ctx context.Context, req *computepb.SetNamedPortsInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceGroupsRESTClient) SetNamedPorts(ctx context.Context, req *computepb.SetNamedPortsInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupsSetNamedPortsRequestResource() jsonReq, err := m.Marshal(body) @@ -680,5 +790,156 @@ func (c *instanceGroupsRESTClient) SetNamedPorts(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// InstanceGroupIterator manages a stream of *computepb.InstanceGroup. +type InstanceGroupIterator struct { + items []*computepb.InstanceGroup + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.InstanceGroup, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceGroupIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceGroupIterator) Next() (*computepb.InstanceGroup, error) { + var item *computepb.InstanceGroup + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceGroupIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceGroupIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InstanceGroupsScopedListPair is a holder type for string/*computepb.InstanceGroupsScopedList map entries +type InstanceGroupsScopedListPair struct { + Key string + Value *computepb.InstanceGroupsScopedList +} + +// InstanceGroupsScopedListPairIterator manages a stream of InstanceGroupsScopedListPair. +type InstanceGroupsScopedListPairIterator struct { + items []InstanceGroupsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []InstanceGroupsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceGroupsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceGroupsScopedListPairIterator) Next() (InstanceGroupsScopedListPair, error) { + var item InstanceGroupsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceGroupsScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceGroupsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InstanceWithNamedPortsIterator manages a stream of *computepb.InstanceWithNamedPorts. +type InstanceWithNamedPortsIterator struct { + items []*computepb.InstanceWithNamedPorts + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.InstanceWithNamedPorts, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceWithNamedPortsIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceWithNamedPortsIterator) Next() (*computepb.InstanceWithNamedPorts, error) { + var item *computepb.InstanceWithNamedPorts + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceWithNamedPortsIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceWithNamedPortsIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/instance_groups_client_example_test.go b/compute/apiv1/instance_groups_client_example_test.go index 8e646affefb..74dceb35239 100644 --- a/compute/apiv1/instance_groups_client_example_test.go +++ b/compute/apiv1/instance_groups_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,12 +66,18 @@ func ExampleInstanceGroupsClient_AggregatedList() { req := &computepb.AggregatedListInstanceGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstanceGroupsClient_Delete() { @@ -141,12 +148,18 @@ func ExampleInstanceGroupsClient_List() { req := &computepb.ListInstanceGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstanceGroupsClient_ListInstances() { @@ -160,12 +173,18 @@ func ExampleInstanceGroupsClient_ListInstances() { req := &computepb.ListInstancesInstanceGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListInstances(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListInstances(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstanceGroupsClient_RemoveInstances() { diff --git a/compute/apiv1/instance_templates_client.go b/compute/apiv1/instance_templates_client.go index 72dde6a4c43..cf58ade378a 100644 --- a/compute/apiv1/instance_templates_client.go +++ b/compute/apiv1/instance_templates_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newInstanceTemplatesClientHook clientHook @@ -52,11 +55,11 @@ type internalInstanceTemplatesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteInstanceTemplateRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteInstanceTemplateRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetInstanceTemplateRequest, ...gax.CallOption) (*computepb.InstanceTemplate, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyInstanceTemplateRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertInstanceTemplateRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListInstanceTemplatesRequest, ...gax.CallOption) (*computepb.InstanceTemplateList, error) + Insert(context.Context, *computepb.InsertInstanceTemplateRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListInstanceTemplatesRequest, ...gax.CallOption) *InstanceTemplateIterator SetIamPolicy(context.Context, *computepb.SetIamPolicyInstanceTemplateRequest, ...gax.CallOption) (*computepb.Policy, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsInstanceTemplateRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -96,7 +99,7 @@ func (c *InstanceTemplatesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified instance template. Deleting an instance template is permanent and cannot be undone. It is not possible to delete templates that are already in use by a managed instance group. -func (c *InstanceTemplatesClient) Delete(ctx context.Context, req *computepb.DeleteInstanceTemplateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceTemplatesClient) Delete(ctx context.Context, req *computepb.DeleteInstanceTemplateRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -111,12 +114,12 @@ func (c *InstanceTemplatesClient) GetIamPolicy(ctx context.Context, req *compute } // Insert creates an instance template in the specified project using the data that is included in the request. If you are creating a new template to update an existing instance group, your new instance template must use the same network or, if applicable, the same subnetwork as the original template. -func (c *InstanceTemplatesClient) Insert(ctx context.Context, req *computepb.InsertInstanceTemplateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstanceTemplatesClient) Insert(ctx context.Context, req *computepb.InsertInstanceTemplateRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of instance templates that are contained within the specified project. -func (c *InstanceTemplatesClient) List(ctx context.Context, req *computepb.ListInstanceTemplatesRequest, opts ...gax.CallOption) (*computepb.InstanceTemplateList, error) { +func (c *InstanceTemplatesClient) List(ctx context.Context, req *computepb.ListInstanceTemplatesRequest, opts ...gax.CallOption) *InstanceTemplateIterator { return c.internalClient.List(ctx, req, opts...) } @@ -195,7 +198,7 @@ func (c *instanceTemplatesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified instance template. Deleting an instance template is permanent and cannot be undone. It is not possible to delete templates that are already in use by a managed instance group. -func (c *instanceTemplatesRESTClient) Delete(ctx context.Context, req *computepb.DeleteInstanceTemplateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceTemplatesRESTClient) Delete(ctx context.Context, req *computepb.DeleteInstanceTemplateRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/instanceTemplates/%v", req.GetProject(), req.GetInstanceTemplate()) @@ -235,7 +238,11 @@ func (c *instanceTemplatesRESTClient) Delete(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified instance template. Gets a list of available instance templates by making a list() request. @@ -320,7 +327,7 @@ func (c *instanceTemplatesRESTClient) GetIamPolicy(ctx context.Context, req *com } // Insert creates an instance template in the specified project using the data that is included in the request. If you are creating a new template to update an existing instance group, your new instance template must use the same network or, if applicable, the same subnetwork as the original template. -func (c *instanceTemplatesRESTClient) Insert(ctx context.Context, req *computepb.InsertInstanceTemplateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instanceTemplatesRESTClient) Insert(ctx context.Context, req *computepb.InsertInstanceTemplateRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceTemplateResource() jsonReq, err := m.Marshal(body) @@ -367,63 +374,95 @@ func (c *instanceTemplatesRESTClient) Insert(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of instance templates that are contained within the specified project. -func (c *instanceTemplatesRESTClient) List(ctx context.Context, req *computepb.ListInstanceTemplatesRequest, opts ...gax.CallOption) (*computepb.InstanceTemplateList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/instanceTemplates", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of instance templates that are contained within the specified project. +func (c *instanceTemplatesRESTClient) List(ctx context.Context, req *computepb.ListInstanceTemplatesRequest, opts ...gax.CallOption) *InstanceTemplateIterator { + it := &InstanceTemplateIterator{} + req = proto.Clone(req).(*computepb.ListInstanceTemplatesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceTemplateList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InstanceTemplate, string, error) { + resp := &computepb.InstanceTemplateList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/instanceTemplates", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -513,3 +552,50 @@ func (c *instanceTemplatesRESTClient) TestIamPermissions(ctx context.Context, re return rsp, unm.Unmarshal(buf, rsp) } + +// InstanceTemplateIterator manages a stream of *computepb.InstanceTemplate. +type InstanceTemplateIterator struct { + items []*computepb.InstanceTemplate + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.InstanceTemplate, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceTemplateIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceTemplateIterator) Next() (*computepb.InstanceTemplate, error) { + var item *computepb.InstanceTemplate + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceTemplateIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceTemplateIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/instance_templates_client_example_test.go b/compute/apiv1/instance_templates_client_example_test.go index 3cdbbabf56d..a4616208e71 100644 --- a/compute/apiv1/instance_templates_client_example_test.go +++ b/compute/apiv1/instance_templates_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -122,12 +123,18 @@ func ExampleInstanceTemplatesClient_List() { req := &computepb.ListInstanceTemplatesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstanceTemplatesClient_SetIamPolicy() { diff --git a/compute/apiv1/instances_client.go b/compute/apiv1/instances_client.go index fb05615361d..f742d5d949d 100644 --- a/compute/apiv1/instances_client.go +++ b/compute/apiv1/instances_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newInstancesClientHook clientHook @@ -87,14 +91,14 @@ type internalInstancesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddAccessConfig(context.Context, *computepb.AddAccessConfigInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - AddResourcePolicies(context.Context, *computepb.AddResourcePoliciesInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - AggregatedList(context.Context, *computepb.AggregatedListInstancesRequest, ...gax.CallOption) (*computepb.InstanceAggregatedList, error) - AttachDisk(context.Context, *computepb.AttachDiskInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - BulkInsert(context.Context, *computepb.BulkInsertInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - DeleteAccessConfig(context.Context, *computepb.DeleteAccessConfigInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - DetachDisk(context.Context, *computepb.DetachDiskInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) + AddAccessConfig(context.Context, *computepb.AddAccessConfigInstanceRequest, ...gax.CallOption) (*Operation, error) + AddResourcePolicies(context.Context, *computepb.AddResourcePoliciesInstanceRequest, ...gax.CallOption) (*Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListInstancesRequest, ...gax.CallOption) *InstancesScopedListPairIterator + AttachDisk(context.Context, *computepb.AttachDiskInstanceRequest, ...gax.CallOption) (*Operation, error) + BulkInsert(context.Context, *computepb.BulkInsertInstanceRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteInstanceRequest, ...gax.CallOption) (*Operation, error) + DeleteAccessConfig(context.Context, *computepb.DeleteAccessConfigInstanceRequest, ...gax.CallOption) (*Operation, error) + DetachDisk(context.Context, *computepb.DetachDiskInstanceRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetInstanceRequest, ...gax.CallOption) (*computepb.Instance, error) GetEffectiveFirewalls(context.Context, *computepb.GetEffectiveFirewallsInstanceRequest, ...gax.CallOption) (*computepb.InstancesGetEffectiveFirewallsResponse, error) GetGuestAttributes(context.Context, *computepb.GetGuestAttributesInstanceRequest, ...gax.CallOption) (*computepb.GuestAttributes, error) @@ -102,33 +106,33 @@ type internalInstancesClient interface { GetScreenshot(context.Context, *computepb.GetScreenshotInstanceRequest, ...gax.CallOption) (*computepb.Screenshot, error) GetSerialPortOutput(context.Context, *computepb.GetSerialPortOutputInstanceRequest, ...gax.CallOption) (*computepb.SerialPortOutput, error) GetShieldedInstanceIdentity(context.Context, *computepb.GetShieldedInstanceIdentityInstanceRequest, ...gax.CallOption) (*computepb.ShieldedInstanceIdentity, error) - Insert(context.Context, *computepb.InsertInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListInstancesRequest, ...gax.CallOption) (*computepb.InstanceList, error) - ListReferrers(context.Context, *computepb.ListReferrersInstancesRequest, ...gax.CallOption) (*computepb.InstanceListReferrers, error) - RemoveResourcePolicies(context.Context, *computepb.RemoveResourcePoliciesInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - Reset(context.Context, *computepb.ResetInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetDeletionProtection(context.Context, *computepb.SetDeletionProtectionInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetDiskAutoDelete(context.Context, *computepb.SetDiskAutoDeleteInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertInstanceRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListInstancesRequest, ...gax.CallOption) *InstanceIterator + ListReferrers(context.Context, *computepb.ListReferrersInstancesRequest, ...gax.CallOption) *ReferenceIterator + RemoveResourcePolicies(context.Context, *computepb.RemoveResourcePoliciesInstanceRequest, ...gax.CallOption) (*Operation, error) + Reset(context.Context, *computepb.ResetInstanceRequest, ...gax.CallOption) (*Operation, error) + SetDeletionProtection(context.Context, *computepb.SetDeletionProtectionInstanceRequest, ...gax.CallOption) (*Operation, error) + SetDiskAutoDelete(context.Context, *computepb.SetDiskAutoDeleteInstanceRequest, ...gax.CallOption) (*Operation, error) SetIamPolicy(context.Context, *computepb.SetIamPolicyInstanceRequest, ...gax.CallOption) (*computepb.Policy, error) - SetLabels(context.Context, *computepb.SetLabelsInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetMachineResources(context.Context, *computepb.SetMachineResourcesInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetMachineType(context.Context, *computepb.SetMachineTypeInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetMetadata(context.Context, *computepb.SetMetadataInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetMinCpuPlatform(context.Context, *computepb.SetMinCpuPlatformInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetScheduling(context.Context, *computepb.SetSchedulingInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetServiceAccount(context.Context, *computepb.SetServiceAccountInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetShieldedInstanceIntegrityPolicy(context.Context, *computepb.SetShieldedInstanceIntegrityPolicyInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SetTags(context.Context, *computepb.SetTagsInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - SimulateMaintenanceEvent(context.Context, *computepb.SimulateMaintenanceEventInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - Start(context.Context, *computepb.StartInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - StartWithEncryptionKey(context.Context, *computepb.StartWithEncryptionKeyInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - Stop(context.Context, *computepb.StopInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) + SetLabels(context.Context, *computepb.SetLabelsInstanceRequest, ...gax.CallOption) (*Operation, error) + SetMachineResources(context.Context, *computepb.SetMachineResourcesInstanceRequest, ...gax.CallOption) (*Operation, error) + SetMachineType(context.Context, *computepb.SetMachineTypeInstanceRequest, ...gax.CallOption) (*Operation, error) + SetMetadata(context.Context, *computepb.SetMetadataInstanceRequest, ...gax.CallOption) (*Operation, error) + SetMinCpuPlatform(context.Context, *computepb.SetMinCpuPlatformInstanceRequest, ...gax.CallOption) (*Operation, error) + SetScheduling(context.Context, *computepb.SetSchedulingInstanceRequest, ...gax.CallOption) (*Operation, error) + SetServiceAccount(context.Context, *computepb.SetServiceAccountInstanceRequest, ...gax.CallOption) (*Operation, error) + SetShieldedInstanceIntegrityPolicy(context.Context, *computepb.SetShieldedInstanceIntegrityPolicyInstanceRequest, ...gax.CallOption) (*Operation, error) + SetTags(context.Context, *computepb.SetTagsInstanceRequest, ...gax.CallOption) (*Operation, error) + SimulateMaintenanceEvent(context.Context, *computepb.SimulateMaintenanceEventInstanceRequest, ...gax.CallOption) (*Operation, error) + Start(context.Context, *computepb.StartInstanceRequest, ...gax.CallOption) (*Operation, error) + StartWithEncryptionKey(context.Context, *computepb.StartWithEncryptionKeyInstanceRequest, ...gax.CallOption) (*Operation, error) + Stop(context.Context, *computepb.StopInstanceRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsInstanceRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) - Update(context.Context, *computepb.UpdateInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - UpdateAccessConfig(context.Context, *computepb.UpdateAccessConfigInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - UpdateDisplayDevice(context.Context, *computepb.UpdateDisplayDeviceInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - UpdateNetworkInterface(context.Context, *computepb.UpdateNetworkInterfaceInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - UpdateShieldedInstanceConfig(context.Context, *computepb.UpdateShieldedInstanceConfigInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) + Update(context.Context, *computepb.UpdateInstanceRequest, ...gax.CallOption) (*Operation, error) + UpdateAccessConfig(context.Context, *computepb.UpdateAccessConfigInstanceRequest, ...gax.CallOption) (*Operation, error) + UpdateDisplayDevice(context.Context, *computepb.UpdateDisplayDeviceInstanceRequest, ...gax.CallOption) (*Operation, error) + UpdateNetworkInterface(context.Context, *computepb.UpdateNetworkInterfaceInstanceRequest, ...gax.CallOption) (*Operation, error) + UpdateShieldedInstanceConfig(context.Context, *computepb.UpdateShieldedInstanceConfigInstanceRequest, ...gax.CallOption) (*Operation, error) } // InstancesClient is a client for interacting with Google Compute Engine API. @@ -166,42 +170,42 @@ func (c *InstancesClient) Connection() *grpc.ClientConn { } // AddAccessConfig adds an access config to an instance’s network interface. -func (c *InstancesClient) AddAccessConfig(ctx context.Context, req *computepb.AddAccessConfigInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) AddAccessConfig(ctx context.Context, req *computepb.AddAccessConfigInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddAccessConfig(ctx, req, opts...) } // AddResourcePolicies adds existing resource policies to an instance. You can only add one policy right now which will be applied to this instance for scheduling live migrations. -func (c *InstancesClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddResourcePolicies(ctx, req, opts...) } // AggregatedList retrieves aggregated list of all of the instances in your project across all regions and zones. -func (c *InstancesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstancesRequest, opts ...gax.CallOption) (*computepb.InstanceAggregatedList, error) { +func (c *InstancesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstancesRequest, opts ...gax.CallOption) *InstancesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // AttachDisk attaches an existing Disk resource to an instance. You must first create the disk before you can attach it. It is not possible to create and attach a disk at the same time. For more information, read Adding a persistent disk to your instance. -func (c *InstancesClient) AttachDisk(ctx context.Context, req *computepb.AttachDiskInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) AttachDisk(ctx context.Context, req *computepb.AttachDiskInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AttachDisk(ctx, req, opts...) } // BulkInsert creates multiple instances. Count specifies the number of instances to create. -func (c *InstancesClient) BulkInsert(ctx context.Context, req *computepb.BulkInsertInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) BulkInsert(ctx context.Context, req *computepb.BulkInsertInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.BulkInsert(ctx, req, opts...) } // Delete deletes the specified Instance resource. For more information, see Deleting an instance. -func (c *InstancesClient) Delete(ctx context.Context, req *computepb.DeleteInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) Delete(ctx context.Context, req *computepb.DeleteInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } // DeleteAccessConfig deletes an access config from an instance’s network interface. -func (c *InstancesClient) DeleteAccessConfig(ctx context.Context, req *computepb.DeleteAccessConfigInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) DeleteAccessConfig(ctx context.Context, req *computepb.DeleteAccessConfigInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DeleteAccessConfig(ctx, req, opts...) } // DetachDisk detaches a disk from an instance. -func (c *InstancesClient) DetachDisk(ctx context.Context, req *computepb.DetachDiskInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) DetachDisk(ctx context.Context, req *computepb.DetachDiskInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DetachDisk(ctx, req, opts...) } @@ -241,37 +245,37 @@ func (c *InstancesClient) GetShieldedInstanceIdentity(ctx context.Context, req * } // Insert creates an instance resource in the specified project using the data included in the request. -func (c *InstancesClient) Insert(ctx context.Context, req *computepb.InsertInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) Insert(ctx context.Context, req *computepb.InsertInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of instances contained within the specified zone. -func (c *InstancesClient) List(ctx context.Context, req *computepb.ListInstancesRequest, opts ...gax.CallOption) (*computepb.InstanceList, error) { +func (c *InstancesClient) List(ctx context.Context, req *computepb.ListInstancesRequest, opts ...gax.CallOption) *InstanceIterator { return c.internalClient.List(ctx, req, opts...) } // ListReferrers retrieves a list of resources that refer to the VM instance specified in the request. For example, if the VM instance is part of a managed or unmanaged instance group, the referrers list includes the instance group. For more information, read Viewing referrers to VM instances. -func (c *InstancesClient) ListReferrers(ctx context.Context, req *computepb.ListReferrersInstancesRequest, opts ...gax.CallOption) (*computepb.InstanceListReferrers, error) { +func (c *InstancesClient) ListReferrers(ctx context.Context, req *computepb.ListReferrersInstancesRequest, opts ...gax.CallOption) *ReferenceIterator { return c.internalClient.ListReferrers(ctx, req, opts...) } // RemoveResourcePolicies removes resource policies from an instance. -func (c *InstancesClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemoveResourcePolicies(ctx, req, opts...) } // Reset performs a reset on the instance. This is a hard reset the VM does not do a graceful shutdown. For more information, see Resetting an instance. -func (c *InstancesClient) Reset(ctx context.Context, req *computepb.ResetInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) Reset(ctx context.Context, req *computepb.ResetInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Reset(ctx, req, opts...) } // SetDeletionProtection sets deletion protection on the instance. -func (c *InstancesClient) SetDeletionProtection(ctx context.Context, req *computepb.SetDeletionProtectionInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetDeletionProtection(ctx context.Context, req *computepb.SetDeletionProtectionInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetDeletionProtection(ctx, req, opts...) } // SetDiskAutoDelete sets the auto-delete flag for a disk attached to an instance. -func (c *InstancesClient) SetDiskAutoDelete(ctx context.Context, req *computepb.SetDiskAutoDeleteInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetDiskAutoDelete(ctx context.Context, req *computepb.SetDiskAutoDeleteInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetDiskAutoDelete(ctx, req, opts...) } @@ -281,67 +285,67 @@ func (c *InstancesClient) SetIamPolicy(ctx context.Context, req *computepb.SetIa } // SetLabels sets labels on an instance. To learn more about labels, read the Labeling Resources documentation. -func (c *InstancesClient) SetLabels(ctx context.Context, req *computepb.SetLabelsInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetLabels(ctx context.Context, req *computepb.SetLabelsInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetLabels(ctx, req, opts...) } // SetMachineResources changes the number and/or type of accelerator for a stopped instance to the values specified in the request. -func (c *InstancesClient) SetMachineResources(ctx context.Context, req *computepb.SetMachineResourcesInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetMachineResources(ctx context.Context, req *computepb.SetMachineResourcesInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetMachineResources(ctx, req, opts...) } // SetMachineType changes the machine type for a stopped instance to the machine type specified in the request. -func (c *InstancesClient) SetMachineType(ctx context.Context, req *computepb.SetMachineTypeInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetMachineType(ctx context.Context, req *computepb.SetMachineTypeInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetMachineType(ctx, req, opts...) } // SetMetadata sets metadata for the specified instance to the data included in the request. -func (c *InstancesClient) SetMetadata(ctx context.Context, req *computepb.SetMetadataInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetMetadata(ctx context.Context, req *computepb.SetMetadataInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetMetadata(ctx, req, opts...) } // SetMinCpuPlatform changes the minimum CPU platform that this instance should use. This method can only be called on a stopped instance. For more information, read Specifying a Minimum CPU Platform. -func (c *InstancesClient) SetMinCpuPlatform(ctx context.Context, req *computepb.SetMinCpuPlatformInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetMinCpuPlatform(ctx context.Context, req *computepb.SetMinCpuPlatformInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetMinCpuPlatform(ctx, req, opts...) } // SetScheduling sets an instance’s scheduling options. You can only call this method on a stopped instance, that is, a VM instance that is in a TERMINATED state. See Instance Life Cycle for more information on the possible instance states. -func (c *InstancesClient) SetScheduling(ctx context.Context, req *computepb.SetSchedulingInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetScheduling(ctx context.Context, req *computepb.SetSchedulingInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetScheduling(ctx, req, opts...) } // SetServiceAccount sets the service account on the instance. For more information, read Changing the service account and access scopes for an instance. -func (c *InstancesClient) SetServiceAccount(ctx context.Context, req *computepb.SetServiceAccountInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetServiceAccount(ctx context.Context, req *computepb.SetServiceAccountInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetServiceAccount(ctx, req, opts...) } // SetShieldedInstanceIntegrityPolicy sets the Shielded Instance integrity policy for an instance. You can only use this method on a running instance. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *InstancesClient) SetShieldedInstanceIntegrityPolicy(ctx context.Context, req *computepb.SetShieldedInstanceIntegrityPolicyInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetShieldedInstanceIntegrityPolicy(ctx context.Context, req *computepb.SetShieldedInstanceIntegrityPolicyInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetShieldedInstanceIntegrityPolicy(ctx, req, opts...) } // SetTags sets network tags for the specified instance to the data included in the request. -func (c *InstancesClient) SetTags(ctx context.Context, req *computepb.SetTagsInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SetTags(ctx context.Context, req *computepb.SetTagsInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetTags(ctx, req, opts...) } // SimulateMaintenanceEvent simulates a maintenance event on the instance. -func (c *InstancesClient) SimulateMaintenanceEvent(ctx context.Context, req *computepb.SimulateMaintenanceEventInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) SimulateMaintenanceEvent(ctx context.Context, req *computepb.SimulateMaintenanceEventInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SimulateMaintenanceEvent(ctx, req, opts...) } // Start starts an instance that was stopped using the instances().stop method. For more information, see Restart an instance. -func (c *InstancesClient) Start(ctx context.Context, req *computepb.StartInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) Start(ctx context.Context, req *computepb.StartInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Start(ctx, req, opts...) } // StartWithEncryptionKey starts an instance that was stopped using the instances().stop method. For more information, see Restart an instance. -func (c *InstancesClient) StartWithEncryptionKey(ctx context.Context, req *computepb.StartWithEncryptionKeyInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) StartWithEncryptionKey(ctx context.Context, req *computepb.StartWithEncryptionKeyInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.StartWithEncryptionKey(ctx, req, opts...) } // Stop stops a running instance, shutting it down cleanly, and allows you to restart the instance at a later time. Stopped instances do not incur VM usage charges while they are stopped. However, resources that the VM is using, such as persistent disks and static IP addresses, will continue to be charged until they are deleted. For more information, see Stopping an instance. -func (c *InstancesClient) Stop(ctx context.Context, req *computepb.StopInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) Stop(ctx context.Context, req *computepb.StopInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Stop(ctx, req, opts...) } @@ -351,27 +355,27 @@ func (c *InstancesClient) TestIamPermissions(ctx context.Context, req *computepb } // Update updates an instance only if the necessary resources are available. This method can update only a specific set of instance properties. See Updating a running instance for a list of updatable instance properties. -func (c *InstancesClient) Update(ctx context.Context, req *computepb.UpdateInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) Update(ctx context.Context, req *computepb.UpdateInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } // UpdateAccessConfig updates the specified access config from an instance’s network interface with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *InstancesClient) UpdateAccessConfig(ctx context.Context, req *computepb.UpdateAccessConfigInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) UpdateAccessConfig(ctx context.Context, req *computepb.UpdateAccessConfigInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.UpdateAccessConfig(ctx, req, opts...) } // UpdateDisplayDevice updates the Display config for a VM instance. You can only use this method on a stopped VM instance. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *InstancesClient) UpdateDisplayDevice(ctx context.Context, req *computepb.UpdateDisplayDeviceInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) UpdateDisplayDevice(ctx context.Context, req *computepb.UpdateDisplayDeviceInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.UpdateDisplayDevice(ctx, req, opts...) } // UpdateNetworkInterface updates an instance’s network interface. This method can only update an interface’s alias IP range and attached network. See Modifying alias IP ranges for an existing instance for instructions on changing alias IP ranges. See Migrating a VM between networks for instructions on migrating an interface. This method follows PATCH semantics. -func (c *InstancesClient) UpdateNetworkInterface(ctx context.Context, req *computepb.UpdateNetworkInterfaceInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) UpdateNetworkInterface(ctx context.Context, req *computepb.UpdateNetworkInterfaceInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.UpdateNetworkInterface(ctx, req, opts...) } // UpdateShieldedInstanceConfig updates the Shielded Instance config for an instance. You can only use this method on a stopped instance. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *InstancesClient) UpdateShieldedInstanceConfig(ctx context.Context, req *computepb.UpdateShieldedInstanceConfigInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InstancesClient) UpdateShieldedInstanceConfig(ctx context.Context, req *computepb.UpdateShieldedInstanceConfigInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.UpdateShieldedInstanceConfig(ctx, req, opts...) } @@ -440,7 +444,7 @@ func (c *instancesRESTClient) Connection() *grpc.ClientConn { } // AddAccessConfig adds an access config to an instance’s network interface. -func (c *instancesRESTClient) AddAccessConfig(ctx context.Context, req *computepb.AddAccessConfigInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) AddAccessConfig(ctx context.Context, req *computepb.AddAccessConfigInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAccessConfigResource() jsonReq, err := m.Marshal(body) @@ -490,11 +494,15 @@ func (c *instancesRESTClient) AddAccessConfig(ctx context.Context, req *computep unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // AddResourcePolicies adds existing resource policies to an instance. You can only add one policy right now which will be applied to this instance for scheduling live migrations. -func (c *instancesRESTClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstancesAddResourcePoliciesRequestResource() jsonReq, err := m.Marshal(body) @@ -541,70 +549,109 @@ func (c *instancesRESTClient) AddResourcePolicies(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// AggregatedList retrieves aggregated list of all of the instances in your project across all regions and zones. -func (c *instancesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstancesRequest, opts ...gax.CallOption) (*computepb.InstanceAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/instances", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// AggregatedList retrieves aggregated list of all of the instances in your project across all regions and zones. +func (c *instancesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInstancesRequest, opts ...gax.CallOption) *InstancesScopedListPairIterator { + it := &InstancesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListInstancesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]InstancesScopedListPair, string, error) { + resp := &computepb.InstanceAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/instances", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]InstancesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, InstancesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // AttachDisk attaches an existing Disk resource to an instance. You must first create the disk before you can attach it. It is not possible to create and attach a disk at the same time. For more information, read Adding a persistent disk to your instance. -func (c *instancesRESTClient) AttachDisk(ctx context.Context, req *computepb.AttachDiskInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) AttachDisk(ctx context.Context, req *computepb.AttachDiskInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAttachedDiskResource() jsonReq, err := m.Marshal(body) @@ -654,11 +701,15 @@ func (c *instancesRESTClient) AttachDisk(ctx context.Context, req *computepb.Att unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // BulkInsert creates multiple instances. Count specifies the number of instances to create. -func (c *instancesRESTClient) BulkInsert(ctx context.Context, req *computepb.BulkInsertInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) BulkInsert(ctx context.Context, req *computepb.BulkInsertInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBulkInsertInstanceResourceResource() jsonReq, err := m.Marshal(body) @@ -705,11 +756,15 @@ func (c *instancesRESTClient) BulkInsert(ctx context.Context, req *computepb.Bul unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified Instance resource. For more information, see Deleting an instance. -func (c *instancesRESTClient) Delete(ctx context.Context, req *computepb.DeleteInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) Delete(ctx context.Context, req *computepb.DeleteInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v", req.GetProject(), req.GetZone(), req.GetInstance()) @@ -749,11 +804,15 @@ func (c *instancesRESTClient) Delete(ctx context.Context, req *computepb.DeleteI unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DeleteAccessConfig deletes an access config from an instance’s network interface. -func (c *instancesRESTClient) DeleteAccessConfig(ctx context.Context, req *computepb.DeleteAccessConfigInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) DeleteAccessConfig(ctx context.Context, req *computepb.DeleteAccessConfigInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/deleteAccessConfig", req.GetProject(), req.GetZone(), req.GetInstance()) @@ -799,11 +858,15 @@ func (c *instancesRESTClient) DeleteAccessConfig(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DetachDisk detaches a disk from an instance. -func (c *instancesRESTClient) DetachDisk(ctx context.Context, req *computepb.DetachDiskInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) DetachDisk(ctx context.Context, req *computepb.DetachDiskInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/detachDisk", req.GetProject(), req.GetZone(), req.GetInstance()) @@ -846,7 +909,11 @@ func (c *instancesRESTClient) DetachDisk(ctx context.Context, req *computepb.Det unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified Instance resource. Gets a list of available instances by making a list() request. @@ -1143,7 +1210,7 @@ func (c *instancesRESTClient) GetShieldedInstanceIdentity(ctx context.Context, r } // Insert creates an instance resource in the specified project using the data included in the request. -func (c *instancesRESTClient) Insert(ctx context.Context, req *computepb.InsertInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) Insert(ctx context.Context, req *computepb.InsertInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceResource() jsonReq, err := m.Marshal(body) @@ -1193,123 +1260,183 @@ func (c *instancesRESTClient) Insert(ctx context.Context, req *computepb.InsertI unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of instances contained within the specified zone. -func (c *instancesRESTClient) List(ctx context.Context, req *computepb.ListInstancesRequest, opts ...gax.CallOption) (*computepb.InstanceList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of instances contained within the specified zone. +func (c *instancesRESTClient) List(ctx context.Context, req *computepb.ListInstancesRequest, opts ...gax.CallOption) *InstanceIterator { + it := &InstanceIterator{} + req = proto.Clone(req).(*computepb.ListInstancesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Instance, string, error) { + resp := &computepb.InstanceList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListReferrers retrieves a list of resources that refer to the VM instance specified in the request. For example, if the VM instance is part of a managed or unmanaged instance group, the referrers list includes the instance group. For more information, read Viewing referrers to VM instances. -func (c *instancesRESTClient) ListReferrers(ctx context.Context, req *computepb.ListReferrersInstancesRequest, opts ...gax.CallOption) (*computepb.InstanceListReferrers, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/referrers", req.GetProject(), req.GetZone(), req.GetInstance()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *instancesRESTClient) ListReferrers(ctx context.Context, req *computepb.ListReferrersInstancesRequest, opts ...gax.CallOption) *ReferenceIterator { + it := &ReferenceIterator{} + req = proto.Clone(req).(*computepb.ListReferrersInstancesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InstanceListReferrers{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Reference, string, error) { + resp := &computepb.InstanceListReferrers{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/referrers", req.GetProject(), req.GetZone(), req.GetInstance()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // RemoveResourcePolicies removes resource policies from an instance. -func (c *instancesRESTClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstancesRemoveResourcePoliciesRequestResource() jsonReq, err := m.Marshal(body) @@ -1356,11 +1483,15 @@ func (c *instancesRESTClient) RemoveResourcePolicies(ctx context.Context, req *c unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Reset performs a reset on the instance. This is a hard reset the VM does not do a graceful shutdown. For more information, see Resetting an instance. -func (c *instancesRESTClient) Reset(ctx context.Context, req *computepb.ResetInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) Reset(ctx context.Context, req *computepb.ResetInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/reset", req.GetProject(), req.GetZone(), req.GetInstance()) @@ -1400,11 +1531,15 @@ func (c *instancesRESTClient) Reset(ctx context.Context, req *computepb.ResetIns unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetDeletionProtection sets deletion protection on the instance. -func (c *instancesRESTClient) SetDeletionProtection(ctx context.Context, req *computepb.SetDeletionProtectionInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetDeletionProtection(ctx context.Context, req *computepb.SetDeletionProtectionInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/setDeletionProtection", req.GetProject(), req.GetZone(), req.GetResource()) @@ -1447,11 +1582,15 @@ func (c *instancesRESTClient) SetDeletionProtection(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetDiskAutoDelete sets the auto-delete flag for a disk attached to an instance. -func (c *instancesRESTClient) SetDiskAutoDelete(ctx context.Context, req *computepb.SetDiskAutoDeleteInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetDiskAutoDelete(ctx context.Context, req *computepb.SetDiskAutoDeleteInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/setDiskAutoDelete", req.GetProject(), req.GetZone(), req.GetInstance()) @@ -1497,7 +1636,11 @@ func (c *instancesRESTClient) SetDiskAutoDelete(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -1545,7 +1688,7 @@ func (c *instancesRESTClient) SetIamPolicy(ctx context.Context, req *computepb.S } // SetLabels sets labels on an instance. To learn more about labels, read the Labeling Resources documentation. -func (c *instancesRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstancesSetLabelsRequestResource() jsonReq, err := m.Marshal(body) @@ -1592,11 +1735,15 @@ func (c *instancesRESTClient) SetLabels(ctx context.Context, req *computepb.SetL unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetMachineResources changes the number and/or type of accelerator for a stopped instance to the values specified in the request. -func (c *instancesRESTClient) SetMachineResources(ctx context.Context, req *computepb.SetMachineResourcesInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetMachineResources(ctx context.Context, req *computepb.SetMachineResourcesInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstancesSetMachineResourcesRequestResource() jsonReq, err := m.Marshal(body) @@ -1643,11 +1790,15 @@ func (c *instancesRESTClient) SetMachineResources(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetMachineType changes the machine type for a stopped instance to the machine type specified in the request. -func (c *instancesRESTClient) SetMachineType(ctx context.Context, req *computepb.SetMachineTypeInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetMachineType(ctx context.Context, req *computepb.SetMachineTypeInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstancesSetMachineTypeRequestResource() jsonReq, err := m.Marshal(body) @@ -1694,11 +1845,15 @@ func (c *instancesRESTClient) SetMachineType(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetMetadata sets metadata for the specified instance to the data included in the request. -func (c *instancesRESTClient) SetMetadata(ctx context.Context, req *computepb.SetMetadataInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetMetadata(ctx context.Context, req *computepb.SetMetadataInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetMetadataResource() jsonReq, err := m.Marshal(body) @@ -1745,11 +1900,15 @@ func (c *instancesRESTClient) SetMetadata(ctx context.Context, req *computepb.Se unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetMinCpuPlatform changes the minimum CPU platform that this instance should use. This method can only be called on a stopped instance. For more information, read Specifying a Minimum CPU Platform. -func (c *instancesRESTClient) SetMinCpuPlatform(ctx context.Context, req *computepb.SetMinCpuPlatformInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetMinCpuPlatform(ctx context.Context, req *computepb.SetMinCpuPlatformInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstancesSetMinCpuPlatformRequestResource() jsonReq, err := m.Marshal(body) @@ -1796,11 +1955,15 @@ func (c *instancesRESTClient) SetMinCpuPlatform(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetScheduling sets an instance’s scheduling options. You can only call this method on a stopped instance, that is, a VM instance that is in a TERMINATED state. See Instance Life Cycle for more information on the possible instance states. -func (c *instancesRESTClient) SetScheduling(ctx context.Context, req *computepb.SetSchedulingInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetScheduling(ctx context.Context, req *computepb.SetSchedulingInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSchedulingResource() jsonReq, err := m.Marshal(body) @@ -1847,11 +2010,15 @@ func (c *instancesRESTClient) SetScheduling(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetServiceAccount sets the service account on the instance. For more information, read Changing the service account and access scopes for an instance. -func (c *instancesRESTClient) SetServiceAccount(ctx context.Context, req *computepb.SetServiceAccountInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetServiceAccount(ctx context.Context, req *computepb.SetServiceAccountInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstancesSetServiceAccountRequestResource() jsonReq, err := m.Marshal(body) @@ -1898,11 +2065,15 @@ func (c *instancesRESTClient) SetServiceAccount(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetShieldedInstanceIntegrityPolicy sets the Shielded Instance integrity policy for an instance. You can only use this method on a running instance. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *instancesRESTClient) SetShieldedInstanceIntegrityPolicy(ctx context.Context, req *computepb.SetShieldedInstanceIntegrityPolicyInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetShieldedInstanceIntegrityPolicy(ctx context.Context, req *computepb.SetShieldedInstanceIntegrityPolicyInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetShieldedInstanceIntegrityPolicyResource() jsonReq, err := m.Marshal(body) @@ -1949,11 +2120,15 @@ func (c *instancesRESTClient) SetShieldedInstanceIntegrityPolicy(ctx context.Con unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetTags sets network tags for the specified instance to the data included in the request. -func (c *instancesRESTClient) SetTags(ctx context.Context, req *computepb.SetTagsInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SetTags(ctx context.Context, req *computepb.SetTagsInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTagsResource() jsonReq, err := m.Marshal(body) @@ -2000,11 +2175,15 @@ func (c *instancesRESTClient) SetTags(ctx context.Context, req *computepb.SetTag unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SimulateMaintenanceEvent simulates a maintenance event on the instance. -func (c *instancesRESTClient) SimulateMaintenanceEvent(ctx context.Context, req *computepb.SimulateMaintenanceEventInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) SimulateMaintenanceEvent(ctx context.Context, req *computepb.SimulateMaintenanceEventInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/simulateMaintenanceEvent", req.GetProject(), req.GetZone(), req.GetInstance()) @@ -2037,11 +2216,15 @@ func (c *instancesRESTClient) SimulateMaintenanceEvent(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Start starts an instance that was stopped using the instances().stop method. For more information, see Restart an instance. -func (c *instancesRESTClient) Start(ctx context.Context, req *computepb.StartInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) Start(ctx context.Context, req *computepb.StartInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/start", req.GetProject(), req.GetZone(), req.GetInstance()) @@ -2081,11 +2264,15 @@ func (c *instancesRESTClient) Start(ctx context.Context, req *computepb.StartIns unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // StartWithEncryptionKey starts an instance that was stopped using the instances().stop method. For more information, see Restart an instance. -func (c *instancesRESTClient) StartWithEncryptionKey(ctx context.Context, req *computepb.StartWithEncryptionKeyInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) StartWithEncryptionKey(ctx context.Context, req *computepb.StartWithEncryptionKeyInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstancesStartWithEncryptionKeyRequestResource() jsonReq, err := m.Marshal(body) @@ -2132,11 +2319,15 @@ func (c *instancesRESTClient) StartWithEncryptionKey(ctx context.Context, req *c unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Stop stops a running instance, shutting it down cleanly, and allows you to restart the instance at a later time. Stopped instances do not incur VM usage charges while they are stopped. However, resources that the VM is using, such as persistent disks and static IP addresses, will continue to be charged until they are deleted. For more information, see Stopping an instance. -func (c *instancesRESTClient) Stop(ctx context.Context, req *computepb.StopInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) Stop(ctx context.Context, req *computepb.StopInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/instances/%v/stop", req.GetProject(), req.GetZone(), req.GetInstance()) @@ -2176,7 +2367,11 @@ func (c *instancesRESTClient) Stop(ctx context.Context, req *computepb.StopInsta unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -2224,7 +2419,7 @@ func (c *instancesRESTClient) TestIamPermissions(ctx context.Context, req *compu } // Update updates an instance only if the necessary resources are available. This method can update only a specific set of instance properties. See Updating a running instance for a list of updatable instance properties. -func (c *instancesRESTClient) Update(ctx context.Context, req *computepb.UpdateInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) Update(ctx context.Context, req *computepb.UpdateInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceResource() jsonReq, err := m.Marshal(body) @@ -2277,11 +2472,15 @@ func (c *instancesRESTClient) Update(ctx context.Context, req *computepb.UpdateI unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // UpdateAccessConfig updates the specified access config from an instance’s network interface with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *instancesRESTClient) UpdateAccessConfig(ctx context.Context, req *computepb.UpdateAccessConfigInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) UpdateAccessConfig(ctx context.Context, req *computepb.UpdateAccessConfigInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAccessConfigResource() jsonReq, err := m.Marshal(body) @@ -2331,11 +2530,15 @@ func (c *instancesRESTClient) UpdateAccessConfig(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // UpdateDisplayDevice updates the Display config for a VM instance. You can only use this method on a stopped VM instance. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *instancesRESTClient) UpdateDisplayDevice(ctx context.Context, req *computepb.UpdateDisplayDeviceInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) UpdateDisplayDevice(ctx context.Context, req *computepb.UpdateDisplayDeviceInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetDisplayDeviceResource() jsonReq, err := m.Marshal(body) @@ -2382,11 +2585,15 @@ func (c *instancesRESTClient) UpdateDisplayDevice(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // UpdateNetworkInterface updates an instance’s network interface. This method can only update an interface’s alias IP range and attached network. See Modifying alias IP ranges for an existing instance for instructions on changing alias IP ranges. See Migrating a VM between networks for instructions on migrating an interface. This method follows PATCH semantics. -func (c *instancesRESTClient) UpdateNetworkInterface(ctx context.Context, req *computepb.UpdateNetworkInterfaceInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) UpdateNetworkInterface(ctx context.Context, req *computepb.UpdateNetworkInterfaceInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworkInterfaceResource() jsonReq, err := m.Marshal(body) @@ -2436,11 +2643,15 @@ func (c *instancesRESTClient) UpdateNetworkInterface(ctx context.Context, req *c unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // UpdateShieldedInstanceConfig updates the Shielded Instance config for an instance. You can only use this method on a stopped instance. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *instancesRESTClient) UpdateShieldedInstanceConfig(ctx context.Context, req *computepb.UpdateShieldedInstanceConfigInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *instancesRESTClient) UpdateShieldedInstanceConfig(ctx context.Context, req *computepb.UpdateShieldedInstanceConfigInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetShieldedInstanceConfigResource() jsonReq, err := m.Marshal(body) @@ -2487,5 +2698,156 @@ func (c *instancesRESTClient) UpdateShieldedInstanceConfig(ctx context.Context, unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// InstanceIterator manages a stream of *computepb.Instance. +type InstanceIterator struct { + items []*computepb.Instance + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Instance, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstanceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstanceIterator) Next() (*computepb.Instance, error) { + var item *computepb.Instance + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstanceIterator) bufLen() int { + return len(it.items) +} + +func (it *InstanceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InstancesScopedListPair is a holder type for string/*computepb.InstancesScopedList map entries +type InstancesScopedListPair struct { + Key string + Value *computepb.InstancesScopedList +} + +// InstancesScopedListPairIterator manages a stream of InstancesScopedListPair. +type InstancesScopedListPairIterator struct { + items []InstancesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []InstancesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InstancesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InstancesScopedListPairIterator) Next() (InstancesScopedListPair, error) { + var item InstancesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InstancesScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *InstancesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ReferenceIterator manages a stream of *computepb.Reference. +type ReferenceIterator struct { + items []*computepb.Reference + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Reference, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ReferenceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ReferenceIterator) Next() (*computepb.Reference, error) { + var item *computepb.Reference + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ReferenceIterator) bufLen() int { + return len(it.items) +} + +func (it *ReferenceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/instances_client_example_test.go b/compute/apiv1/instances_client_example_test.go index 3728bb87319..ab022576d34 100644 --- a/compute/apiv1/instances_client_example_test.go +++ b/compute/apiv1/instances_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -84,12 +85,18 @@ func ExampleInstancesClient_AggregatedList() { req := &computepb.AggregatedListInstancesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstancesClient_AttachDisk() { @@ -350,12 +357,18 @@ func ExampleInstancesClient_List() { req := &computepb.ListInstancesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstancesClient_ListReferrers() { @@ -369,12 +382,18 @@ func ExampleInstancesClient_ListReferrers() { req := &computepb.ListReferrersInstancesRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListReferrers(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListReferrers(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInstancesClient_RemoveResourcePolicies() { diff --git a/compute/apiv1/interconnect_attachments_client.go b/compute/apiv1/interconnect_attachments_client.go index f0d5ab72e94..b6e6ba3d84e 100644 --- a/compute/apiv1/interconnect_attachments_client.go +++ b/compute/apiv1/interconnect_attachments_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newInterconnectAttachmentsClientHook clientHook @@ -51,12 +55,12 @@ type internalInterconnectAttachmentsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListInterconnectAttachmentsRequest, ...gax.CallOption) (*computepb.InterconnectAttachmentAggregatedList, error) - Delete(context.Context, *computepb.DeleteInterconnectAttachmentRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListInterconnectAttachmentsRequest, ...gax.CallOption) *InterconnectAttachmentsScopedListPairIterator + Delete(context.Context, *computepb.DeleteInterconnectAttachmentRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetInterconnectAttachmentRequest, ...gax.CallOption) (*computepb.InterconnectAttachment, error) - Insert(context.Context, *computepb.InsertInterconnectAttachmentRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListInterconnectAttachmentsRequest, ...gax.CallOption) (*computepb.InterconnectAttachmentList, error) - Patch(context.Context, *computepb.PatchInterconnectAttachmentRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertInterconnectAttachmentRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListInterconnectAttachmentsRequest, ...gax.CallOption) *InterconnectAttachmentIterator + Patch(context.Context, *computepb.PatchInterconnectAttachmentRequest, ...gax.CallOption) (*Operation, error) } // InterconnectAttachmentsClient is a client for interacting with Google Compute Engine API. @@ -94,12 +98,12 @@ func (c *InterconnectAttachmentsClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of interconnect attachments. -func (c *InterconnectAttachmentsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInterconnectAttachmentsRequest, opts ...gax.CallOption) (*computepb.InterconnectAttachmentAggregatedList, error) { +func (c *InterconnectAttachmentsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInterconnectAttachmentsRequest, opts ...gax.CallOption) *InterconnectAttachmentsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified interconnect attachment. -func (c *InterconnectAttachmentsClient) Delete(ctx context.Context, req *computepb.DeleteInterconnectAttachmentRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InterconnectAttachmentsClient) Delete(ctx context.Context, req *computepb.DeleteInterconnectAttachmentRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -109,17 +113,17 @@ func (c *InterconnectAttachmentsClient) Get(ctx context.Context, req *computepb. } // Insert creates an InterconnectAttachment in the specified project using the data included in the request. -func (c *InterconnectAttachmentsClient) Insert(ctx context.Context, req *computepb.InsertInterconnectAttachmentRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InterconnectAttachmentsClient) Insert(ctx context.Context, req *computepb.InsertInterconnectAttachmentRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of interconnect attachments contained within the specified region. -func (c *InterconnectAttachmentsClient) List(ctx context.Context, req *computepb.ListInterconnectAttachmentsRequest, opts ...gax.CallOption) (*computepb.InterconnectAttachmentList, error) { +func (c *InterconnectAttachmentsClient) List(ctx context.Context, req *computepb.ListInterconnectAttachmentsRequest, opts ...gax.CallOption) *InterconnectAttachmentIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates the specified interconnect attachment with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *InterconnectAttachmentsClient) Patch(ctx context.Context, req *computepb.PatchInterconnectAttachmentRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InterconnectAttachmentsClient) Patch(ctx context.Context, req *computepb.PatchInterconnectAttachmentRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -188,66 +192,101 @@ func (c *interconnectAttachmentsRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of interconnect attachments. -func (c *interconnectAttachmentsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInterconnectAttachmentsRequest, opts ...gax.CallOption) (*computepb.InterconnectAttachmentAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/interconnectAttachments", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *interconnectAttachmentsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListInterconnectAttachmentsRequest, opts ...gax.CallOption) *InterconnectAttachmentsScopedListPairIterator { + it := &InterconnectAttachmentsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListInterconnectAttachmentsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InterconnectAttachmentAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]InterconnectAttachmentsScopedListPair, string, error) { + resp := &computepb.InterconnectAttachmentAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/interconnectAttachments", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]InterconnectAttachmentsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, InterconnectAttachmentsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified interconnect attachment. -func (c *interconnectAttachmentsRESTClient) Delete(ctx context.Context, req *computepb.DeleteInterconnectAttachmentRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *interconnectAttachmentsRESTClient) Delete(ctx context.Context, req *computepb.DeleteInterconnectAttachmentRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/interconnectAttachments/%v", req.GetProject(), req.GetRegion(), req.GetInterconnectAttachment()) @@ -287,7 +326,11 @@ func (c *interconnectAttachmentsRESTClient) Delete(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified interconnect attachment. @@ -328,7 +371,7 @@ func (c *interconnectAttachmentsRESTClient) Get(ctx context.Context, req *comput } // Insert creates an InterconnectAttachment in the specified project using the data included in the request. -func (c *interconnectAttachmentsRESTClient) Insert(ctx context.Context, req *computepb.InsertInterconnectAttachmentRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *interconnectAttachmentsRESTClient) Insert(ctx context.Context, req *computepb.InsertInterconnectAttachmentRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInterconnectAttachmentResource() jsonReq, err := m.Marshal(body) @@ -378,67 +421,99 @@ func (c *interconnectAttachmentsRESTClient) Insert(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of interconnect attachments contained within the specified region. -func (c *interconnectAttachmentsRESTClient) List(ctx context.Context, req *computepb.ListInterconnectAttachmentsRequest, opts ...gax.CallOption) (*computepb.InterconnectAttachmentList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/interconnectAttachments", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of interconnect attachments contained within the specified region. +func (c *interconnectAttachmentsRESTClient) List(ctx context.Context, req *computepb.ListInterconnectAttachmentsRequest, opts ...gax.CallOption) *InterconnectAttachmentIterator { + it := &InterconnectAttachmentIterator{} + req = proto.Clone(req).(*computepb.ListInterconnectAttachmentsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InterconnectAttachmentList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InterconnectAttachment, string, error) { + resp := &computepb.InterconnectAttachmentList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/interconnectAttachments", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates the specified interconnect attachment with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *interconnectAttachmentsRESTClient) Patch(ctx context.Context, req *computepb.PatchInterconnectAttachmentRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *interconnectAttachmentsRESTClient) Patch(ctx context.Context, req *computepb.PatchInterconnectAttachmentRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInterconnectAttachmentResource() jsonReq, err := m.Marshal(body) @@ -485,5 +560,109 @@ func (c *interconnectAttachmentsRESTClient) Patch(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// InterconnectAttachmentIterator manages a stream of *computepb.InterconnectAttachment. +type InterconnectAttachmentIterator struct { + items []*computepb.InterconnectAttachment + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.InterconnectAttachment, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InterconnectAttachmentIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InterconnectAttachmentIterator) Next() (*computepb.InterconnectAttachment, error) { + var item *computepb.InterconnectAttachment + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InterconnectAttachmentIterator) bufLen() int { + return len(it.items) +} + +func (it *InterconnectAttachmentIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// InterconnectAttachmentsScopedListPair is a holder type for string/*computepb.InterconnectAttachmentsScopedList map entries +type InterconnectAttachmentsScopedListPair struct { + Key string + Value *computepb.InterconnectAttachmentsScopedList +} + +// InterconnectAttachmentsScopedListPairIterator manages a stream of InterconnectAttachmentsScopedListPair. +type InterconnectAttachmentsScopedListPairIterator struct { + items []InterconnectAttachmentsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []InterconnectAttachmentsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InterconnectAttachmentsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InterconnectAttachmentsScopedListPairIterator) Next() (InterconnectAttachmentsScopedListPair, error) { + var item InterconnectAttachmentsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InterconnectAttachmentsScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *InterconnectAttachmentsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/interconnect_attachments_client_example_test.go b/compute/apiv1/interconnect_attachments_client_example_test.go index 0f480c1a58a..8754aded62d 100644 --- a/compute/apiv1/interconnect_attachments_client_example_test.go +++ b/compute/apiv1/interconnect_attachments_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleInterconnectAttachmentsClient_AggregatedList() { req := &computepb.AggregatedListInterconnectAttachmentsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInterconnectAttachmentsClient_Delete() { @@ -122,12 +129,18 @@ func ExampleInterconnectAttachmentsClient_List() { req := &computepb.ListInterconnectAttachmentsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInterconnectAttachmentsClient_Patch() { diff --git a/compute/apiv1/interconnect_locations_client.go b/compute/apiv1/interconnect_locations_client.go index 0e42808c576..7af75ffdecf 100644 --- a/compute/apiv1/interconnect_locations_client.go +++ b/compute/apiv1/interconnect_locations_client.go @@ -20,10 +20,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +33,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newInterconnectLocationsClientHook clientHook @@ -47,7 +50,7 @@ type internalInterconnectLocationsClient interface { setGoogleClientInfo(...string) Connection() *grpc.ClientConn Get(context.Context, *computepb.GetInterconnectLocationRequest, ...gax.CallOption) (*computepb.InterconnectLocation, error) - List(context.Context, *computepb.ListInterconnectLocationsRequest, ...gax.CallOption) (*computepb.InterconnectLocationList, error) + List(context.Context, *computepb.ListInterconnectLocationsRequest, ...gax.CallOption) *InterconnectLocationIterator } // InterconnectLocationsClient is a client for interacting with Google Compute Engine API. @@ -90,7 +93,7 @@ func (c *InterconnectLocationsClient) Get(ctx context.Context, req *computepb.Ge } // List retrieves the list of interconnect locations available to the specified project. -func (c *InterconnectLocationsClient) List(ctx context.Context, req *computepb.ListInterconnectLocationsRequest, opts ...gax.CallOption) (*computepb.InterconnectLocationList, error) { +func (c *InterconnectLocationsClient) List(ctx context.Context, req *computepb.ListInterconnectLocationsRequest, opts ...gax.CallOption) *InterconnectLocationIterator { return c.internalClient.List(ctx, req, opts...) } @@ -196,57 +199,132 @@ func (c *interconnectLocationsRESTClient) Get(ctx context.Context, req *computep } // List retrieves the list of interconnect locations available to the specified project. -func (c *interconnectLocationsRESTClient) List(ctx context.Context, req *computepb.ListInterconnectLocationsRequest, opts ...gax.CallOption) (*computepb.InterconnectLocationList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/interconnectLocations", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *interconnectLocationsRESTClient) List(ctx context.Context, req *computepb.ListInterconnectLocationsRequest, opts ...gax.CallOption) *InterconnectLocationIterator { + it := &InterconnectLocationIterator{} + req = proto.Clone(req).(*computepb.ListInterconnectLocationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InterconnectLocation, string, error) { + resp := &computepb.InterconnectLocationList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/interconnectLocations", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// InterconnectLocationIterator manages a stream of *computepb.InterconnectLocation. +type InterconnectLocationIterator struct { + items []*computepb.InterconnectLocation + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.InterconnectLocation, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InterconnectLocationIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InterconnectLocationIterator) Next() (*computepb.InterconnectLocation, error) { + var item *computepb.InterconnectLocation + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InterconnectLocationList{} +func (it *InterconnectLocationIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *InterconnectLocationIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/interconnect_locations_client_example_test.go b/compute/apiv1/interconnect_locations_client_example_test.go index 2c48d43fbb8..14ff03e143d 100644 --- a/compute/apiv1/interconnect_locations_client_example_test.go +++ b/compute/apiv1/interconnect_locations_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,10 +66,16 @@ func ExampleInterconnectLocationsClient_List() { req := &computepb.ListInterconnectLocationsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/interconnects_client.go b/compute/apiv1/interconnects_client.go index 67eac04c6bd..7c10c23aef0 100644 --- a/compute/apiv1/interconnects_client.go +++ b/compute/apiv1/interconnects_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newInterconnectsClientHook clientHook @@ -51,12 +54,12 @@ type internalInterconnectsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteInterconnectRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteInterconnectRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetInterconnectRequest, ...gax.CallOption) (*computepb.Interconnect, error) GetDiagnostics(context.Context, *computepb.GetDiagnosticsInterconnectRequest, ...gax.CallOption) (*computepb.InterconnectsGetDiagnosticsResponse, error) - Insert(context.Context, *computepb.InsertInterconnectRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListInterconnectsRequest, ...gax.CallOption) (*computepb.InterconnectList, error) - Patch(context.Context, *computepb.PatchInterconnectRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertInterconnectRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListInterconnectsRequest, ...gax.CallOption) *InterconnectIterator + Patch(context.Context, *computepb.PatchInterconnectRequest, ...gax.CallOption) (*Operation, error) } // InterconnectsClient is a client for interacting with Google Compute Engine API. @@ -94,7 +97,7 @@ func (c *InterconnectsClient) Connection() *grpc.ClientConn { } // Delete deletes the specified interconnect. -func (c *InterconnectsClient) Delete(ctx context.Context, req *computepb.DeleteInterconnectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InterconnectsClient) Delete(ctx context.Context, req *computepb.DeleteInterconnectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -109,17 +112,17 @@ func (c *InterconnectsClient) GetDiagnostics(ctx context.Context, req *computepb } // Insert creates a Interconnect in the specified project using the data included in the request. -func (c *InterconnectsClient) Insert(ctx context.Context, req *computepb.InsertInterconnectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InterconnectsClient) Insert(ctx context.Context, req *computepb.InsertInterconnectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of interconnect available to the specified project. -func (c *InterconnectsClient) List(ctx context.Context, req *computepb.ListInterconnectsRequest, opts ...gax.CallOption) (*computepb.InterconnectList, error) { +func (c *InterconnectsClient) List(ctx context.Context, req *computepb.ListInterconnectsRequest, opts ...gax.CallOption) *InterconnectIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates the specified interconnect with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *InterconnectsClient) Patch(ctx context.Context, req *computepb.PatchInterconnectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *InterconnectsClient) Patch(ctx context.Context, req *computepb.PatchInterconnectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -188,7 +191,7 @@ func (c *interconnectsRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified interconnect. -func (c *interconnectsRESTClient) Delete(ctx context.Context, req *computepb.DeleteInterconnectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *interconnectsRESTClient) Delete(ctx context.Context, req *computepb.DeleteInterconnectRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/interconnects/%v", req.GetProject(), req.GetInterconnect()) @@ -228,7 +231,11 @@ func (c *interconnectsRESTClient) Delete(ctx context.Context, req *computepb.Del unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified interconnect. Get a list of available interconnects by making a list() request. @@ -306,7 +313,7 @@ func (c *interconnectsRESTClient) GetDiagnostics(ctx context.Context, req *compu } // Insert creates a Interconnect in the specified project using the data included in the request. -func (c *interconnectsRESTClient) Insert(ctx context.Context, req *computepb.InsertInterconnectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *interconnectsRESTClient) Insert(ctx context.Context, req *computepb.InsertInterconnectRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInterconnectResource() jsonReq, err := m.Marshal(body) @@ -353,67 +360,99 @@ func (c *interconnectsRESTClient) Insert(ctx context.Context, req *computepb.Ins unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of interconnect available to the specified project. -func (c *interconnectsRESTClient) List(ctx context.Context, req *computepb.ListInterconnectsRequest, opts ...gax.CallOption) (*computepb.InterconnectList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/interconnects", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of interconnect available to the specified project. +func (c *interconnectsRESTClient) List(ctx context.Context, req *computepb.ListInterconnectsRequest, opts ...gax.CallOption) *InterconnectIterator { + it := &InterconnectIterator{} + req = proto.Clone(req).(*computepb.ListInterconnectsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.InterconnectList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Interconnect, string, error) { + resp := &computepb.InterconnectList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/interconnects", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates the specified interconnect with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *interconnectsRESTClient) Patch(ctx context.Context, req *computepb.PatchInterconnectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *interconnectsRESTClient) Patch(ctx context.Context, req *computepb.PatchInterconnectRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInterconnectResource() jsonReq, err := m.Marshal(body) @@ -460,5 +499,56 @@ func (c *interconnectsRESTClient) Patch(ctx context.Context, req *computepb.Patc unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// InterconnectIterator manages a stream of *computepb.Interconnect. +type InterconnectIterator struct { + items []*computepb.Interconnect + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Interconnect, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *InterconnectIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *InterconnectIterator) Next() (*computepb.Interconnect, error) { + var item *computepb.Interconnect + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *InterconnectIterator) bufLen() int { + return len(it.items) +} + +func (it *InterconnectIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/interconnects_client_example_test.go b/compute/apiv1/interconnects_client_example_test.go index dca1482656b..7ab288bdc21 100644 --- a/compute/apiv1/interconnects_client_example_test.go +++ b/compute/apiv1/interconnects_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -122,12 +123,18 @@ func ExampleInterconnectsClient_List() { req := &computepb.ListInterconnectsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleInterconnectsClient_Patch() { diff --git a/compute/apiv1/licenses_client.go b/compute/apiv1/licenses_client.go index c45a2062882..2ab27fea431 100644 --- a/compute/apiv1/licenses_client.go +++ b/compute/apiv1/licenses_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newLicensesClientHook clientHook @@ -52,11 +55,11 @@ type internalLicensesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteLicenseRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteLicenseRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetLicenseRequest, ...gax.CallOption) (*computepb.License, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyLicenseRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertLicenseRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListLicensesRequest, ...gax.CallOption) (*computepb.LicensesListResponse, error) + Insert(context.Context, *computepb.InsertLicenseRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListLicensesRequest, ...gax.CallOption) *LicenseIterator SetIamPolicy(context.Context, *computepb.SetIamPolicyLicenseRequest, ...gax.CallOption) (*computepb.Policy, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsLicenseRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -96,7 +99,7 @@ func (c *LicensesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified license. Caution This resource is intended for use only by third-party partners who are creating Cloud Marketplace images. -func (c *LicensesClient) Delete(ctx context.Context, req *computepb.DeleteLicenseRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *LicensesClient) Delete(ctx context.Context, req *computepb.DeleteLicenseRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -111,12 +114,12 @@ func (c *LicensesClient) GetIamPolicy(ctx context.Context, req *computepb.GetIam } // Insert create a License resource in the specified project. Caution This resource is intended for use only by third-party partners who are creating Cloud Marketplace images. -func (c *LicensesClient) Insert(ctx context.Context, req *computepb.InsertLicenseRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *LicensesClient) Insert(ctx context.Context, req *computepb.InsertLicenseRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of licenses available in the specified project. This method does not get any licenses that belong to other projects, including licenses attached to publicly-available images, like Debian 9. If you want to get a list of publicly-available licenses, use this method to make a request to the respective image project, such as debian-cloud or windows-cloud. Caution This resource is intended for use only by third-party partners who are creating Cloud Marketplace images. -func (c *LicensesClient) List(ctx context.Context, req *computepb.ListLicensesRequest, opts ...gax.CallOption) (*computepb.LicensesListResponse, error) { +func (c *LicensesClient) List(ctx context.Context, req *computepb.ListLicensesRequest, opts ...gax.CallOption) *LicenseIterator { return c.internalClient.List(ctx, req, opts...) } @@ -195,7 +198,7 @@ func (c *licensesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified license. Caution This resource is intended for use only by third-party partners who are creating Cloud Marketplace images. -func (c *licensesRESTClient) Delete(ctx context.Context, req *computepb.DeleteLicenseRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *licensesRESTClient) Delete(ctx context.Context, req *computepb.DeleteLicenseRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/licenses/%v", req.GetProject(), req.GetLicense()) @@ -235,7 +238,11 @@ func (c *licensesRESTClient) Delete(ctx context.Context, req *computepb.DeleteLi unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified License resource. Caution This resource is intended for use only by third-party partners who are creating Cloud Marketplace images. @@ -320,7 +327,7 @@ func (c *licensesRESTClient) GetIamPolicy(ctx context.Context, req *computepb.Ge } // Insert create a License resource in the specified project. Caution This resource is intended for use only by third-party partners who are creating Cloud Marketplace images. -func (c *licensesRESTClient) Insert(ctx context.Context, req *computepb.InsertLicenseRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *licensesRESTClient) Insert(ctx context.Context, req *computepb.InsertLicenseRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetLicenseResource() jsonReq, err := m.Marshal(body) @@ -367,63 +374,95 @@ func (c *licensesRESTClient) Insert(ctx context.Context, req *computepb.InsertLi unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of licenses available in the specified project. This method does not get any licenses that belong to other projects, including licenses attached to publicly-available images, like Debian 9. If you want to get a list of publicly-available licenses, use this method to make a request to the respective image project, such as debian-cloud or windows-cloud. Caution This resource is intended for use only by third-party partners who are creating Cloud Marketplace images. -func (c *licensesRESTClient) List(ctx context.Context, req *computepb.ListLicensesRequest, opts ...gax.CallOption) (*computepb.LicensesListResponse, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/licenses", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of licenses available in the specified project. This method does not get any licenses that belong to other projects, including licenses attached to publicly-available images, like Debian 9. If you want to get a list of publicly-available licenses, use this method to make a request to the respective image project, such as debian-cloud or windows-cloud. Caution This resource is intended for use only by third-party partners who are creating Cloud Marketplace images. +func (c *licensesRESTClient) List(ctx context.Context, req *computepb.ListLicensesRequest, opts ...gax.CallOption) *LicenseIterator { + it := &LicenseIterator{} + req = proto.Clone(req).(*computepb.ListLicensesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.LicensesListResponse{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.License, string, error) { + resp := &computepb.LicensesListResponse{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/licenses", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. Caution This resource is intended for use only by third-party partners who are creating Cloud Marketplace images. @@ -513,3 +552,50 @@ func (c *licensesRESTClient) TestIamPermissions(ctx context.Context, req *comput return rsp, unm.Unmarshal(buf, rsp) } + +// LicenseIterator manages a stream of *computepb.License. +type LicenseIterator struct { + items []*computepb.License + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.License, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *LicenseIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *LicenseIterator) Next() (*computepb.License, error) { + var item *computepb.License + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *LicenseIterator) bufLen() int { + return len(it.items) +} + +func (it *LicenseIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/licenses_client_example_test.go b/compute/apiv1/licenses_client_example_test.go index 82f80b1944f..9cfba6fef0b 100644 --- a/compute/apiv1/licenses_client_example_test.go +++ b/compute/apiv1/licenses_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -122,12 +123,18 @@ func ExampleLicensesClient_List() { req := &computepb.ListLicensesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleLicensesClient_SetIamPolicy() { diff --git a/compute/apiv1/machine_types_client.go b/compute/apiv1/machine_types_client.go index 22b9b2e9607..8e88eb8cc78 100644 --- a/compute/apiv1/machine_types_client.go +++ b/compute/apiv1/machine_types_client.go @@ -20,10 +20,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newMachineTypesClientHook clientHook @@ -47,9 +51,9 @@ type internalMachineTypesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListMachineTypesRequest, ...gax.CallOption) (*computepb.MachineTypeAggregatedList, error) + AggregatedList(context.Context, *computepb.AggregatedListMachineTypesRequest, ...gax.CallOption) *MachineTypesScopedListPairIterator Get(context.Context, *computepb.GetMachineTypeRequest, ...gax.CallOption) (*computepb.MachineType, error) - List(context.Context, *computepb.ListMachineTypesRequest, ...gax.CallOption) (*computepb.MachineTypeList, error) + List(context.Context, *computepb.ListMachineTypesRequest, ...gax.CallOption) *MachineTypeIterator } // MachineTypesClient is a client for interacting with Google Compute Engine API. @@ -87,7 +91,7 @@ func (c *MachineTypesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of machine types. -func (c *MachineTypesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListMachineTypesRequest, opts ...gax.CallOption) (*computepb.MachineTypeAggregatedList, error) { +func (c *MachineTypesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListMachineTypesRequest, opts ...gax.CallOption) *MachineTypesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } @@ -97,7 +101,7 @@ func (c *MachineTypesClient) Get(ctx context.Context, req *computepb.GetMachineT } // List retrieves a list of machine types available to the specified project. -func (c *MachineTypesClient) List(ctx context.Context, req *computepb.ListMachineTypesRequest, opts ...gax.CallOption) (*computepb.MachineTypeList, error) { +func (c *MachineTypesClient) List(ctx context.Context, req *computepb.ListMachineTypesRequest, opts ...gax.CallOption) *MachineTypeIterator { return c.internalClient.List(ctx, req, opts...) } @@ -166,62 +170,97 @@ func (c *machineTypesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of machine types. -func (c *machineTypesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListMachineTypesRequest, opts ...gax.CallOption) (*computepb.MachineTypeAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/machineTypes", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +func (c *machineTypesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListMachineTypesRequest, opts ...gax.CallOption) *MachineTypesScopedListPairIterator { + it := &MachineTypesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListMachineTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]MachineTypesScopedListPair, string, error) { + resp := &computepb.MachineTypeAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/machineTypes", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]MachineTypesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, MachineTypesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.MachineTypeAggregatedList{} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - return rsp, unm.Unmarshal(buf, rsp) + return it } // Get returns the specified machine type. Gets a list of available machine types by making a list() request. @@ -262,57 +301,185 @@ func (c *machineTypesRESTClient) Get(ctx context.Context, req *computepb.GetMach } // List retrieves a list of machine types available to the specified project. -func (c *machineTypesRESTClient) List(ctx context.Context, req *computepb.ListMachineTypesRequest, opts ...gax.CallOption) (*computepb.MachineTypeList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/machineTypes", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *machineTypesRESTClient) List(ctx context.Context, req *computepb.ListMachineTypesRequest, opts ...gax.CallOption) *MachineTypeIterator { + it := &MachineTypeIterator{} + req = proto.Clone(req).(*computepb.ListMachineTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.MachineType, string, error) { + resp := &computepb.MachineTypeList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/machineTypes", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// MachineTypeIterator manages a stream of *computepb.MachineType. +type MachineTypeIterator struct { + items []*computepb.MachineType + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.MachineType, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *MachineTypeIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *MachineTypeIterator) Next() (*computepb.MachineType, error) { + var item *computepb.MachineType + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +func (it *MachineTypeIterator) bufLen() int { + return len(it.items) +} + +func (it *MachineTypeIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// MachineTypesScopedListPair is a holder type for string/*computepb.MachineTypesScopedList map entries +type MachineTypesScopedListPair struct { + Key string + Value *computepb.MachineTypesScopedList +} + +// MachineTypesScopedListPairIterator manages a stream of MachineTypesScopedListPair. +type MachineTypesScopedListPairIterator struct { + items []MachineTypesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []MachineTypesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *MachineTypesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *MachineTypesScopedListPairIterator) Next() (MachineTypesScopedListPair, error) { + var item MachineTypesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.MachineTypeList{} +func (it *MachineTypesScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *MachineTypesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/machine_types_client_example_test.go b/compute/apiv1/machine_types_client_example_test.go index 858b4032b5c..c79729ef92d 100644 --- a/compute/apiv1/machine_types_client_example_test.go +++ b/compute/apiv1/machine_types_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleMachineTypesClient_AggregatedList() { req := &computepb.AggregatedListMachineTypesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleMachineTypesClient_Get() { @@ -84,10 +91,16 @@ func ExampleMachineTypesClient_List() { req := &computepb.ListMachineTypesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/network_endpoint_groups_client.go b/compute/apiv1/network_endpoint_groups_client.go index 7b76a2e8f10..88e8ba95a0f 100644 --- a/compute/apiv1/network_endpoint_groups_client.go +++ b/compute/apiv1/network_endpoint_groups_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newNetworkEndpointGroupsClientHook clientHook @@ -54,14 +58,14 @@ type internalNetworkEndpointGroupsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListNetworkEndpointGroupsRequest, ...gax.CallOption) (*computepb.NetworkEndpointGroupAggregatedList, error) - AttachNetworkEndpoints(context.Context, *computepb.AttachNetworkEndpointsNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - DetachNetworkEndpoints(context.Context, *computepb.DetachNetworkEndpointsNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListNetworkEndpointGroupsRequest, ...gax.CallOption) *NetworkEndpointGroupsScopedListPairIterator + AttachNetworkEndpoints(context.Context, *computepb.AttachNetworkEndpointsNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) + DetachNetworkEndpoints(context.Context, *computepb.DetachNetworkEndpointsNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.NetworkEndpointGroup, error) - Insert(context.Context, *computepb.InsertNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListNetworkEndpointGroupsRequest, ...gax.CallOption) (*computepb.NetworkEndpointGroupList, error) - ListNetworkEndpoints(context.Context, *computepb.ListNetworkEndpointsNetworkEndpointGroupsRequest, ...gax.CallOption) (*computepb.NetworkEndpointGroupsListNetworkEndpoints, error) + Insert(context.Context, *computepb.InsertNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListNetworkEndpointGroupsRequest, ...gax.CallOption) *NetworkEndpointGroupIterator + ListNetworkEndpoints(context.Context, *computepb.ListNetworkEndpointsNetworkEndpointGroupsRequest, ...gax.CallOption) *NetworkEndpointWithHealthStatusIterator TestIamPermissions(context.Context, *computepb.TestIamPermissionsNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -100,22 +104,22 @@ func (c *NetworkEndpointGroupsClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of network endpoint groups and sorts them by zone. -func (c *NetworkEndpointGroupsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupAggregatedList, error) { +func (c *NetworkEndpointGroupsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointGroupsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // AttachNetworkEndpoints attach a list of network endpoints to the specified network endpoint group. -func (c *NetworkEndpointGroupsClient) AttachNetworkEndpoints(ctx context.Context, req *computepb.AttachNetworkEndpointsNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworkEndpointGroupsClient) AttachNetworkEndpoints(ctx context.Context, req *computepb.AttachNetworkEndpointsNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AttachNetworkEndpoints(ctx, req, opts...) } // Delete deletes the specified network endpoint group. The network endpoints in the NEG and the VM instances they belong to are not terminated when the NEG is deleted. Note that the NEG cannot be deleted if there are backend services referencing it. -func (c *NetworkEndpointGroupsClient) Delete(ctx context.Context, req *computepb.DeleteNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworkEndpointGroupsClient) Delete(ctx context.Context, req *computepb.DeleteNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } // DetachNetworkEndpoints detach a list of network endpoints from the specified network endpoint group. -func (c *NetworkEndpointGroupsClient) DetachNetworkEndpoints(ctx context.Context, req *computepb.DetachNetworkEndpointsNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworkEndpointGroupsClient) DetachNetworkEndpoints(ctx context.Context, req *computepb.DetachNetworkEndpointsNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DetachNetworkEndpoints(ctx, req, opts...) } @@ -125,17 +129,17 @@ func (c *NetworkEndpointGroupsClient) Get(ctx context.Context, req *computepb.Ge } // Insert creates a network endpoint group in the specified project using the parameters that are included in the request. -func (c *NetworkEndpointGroupsClient) Insert(ctx context.Context, req *computepb.InsertNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworkEndpointGroupsClient) Insert(ctx context.Context, req *computepb.InsertNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of network endpoint groups that are located in the specified project and zone. -func (c *NetworkEndpointGroupsClient) List(ctx context.Context, req *computepb.ListNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupList, error) { +func (c *NetworkEndpointGroupsClient) List(ctx context.Context, req *computepb.ListNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointGroupIterator { return c.internalClient.List(ctx, req, opts...) } // ListNetworkEndpoints lists the network endpoints in the specified network endpoint group. -func (c *NetworkEndpointGroupsClient) ListNetworkEndpoints(ctx context.Context, req *computepb.ListNetworkEndpointsNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupsListNetworkEndpoints, error) { +func (c *NetworkEndpointGroupsClient) ListNetworkEndpoints(ctx context.Context, req *computepb.ListNetworkEndpointsNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointWithHealthStatusIterator { return c.internalClient.ListNetworkEndpoints(ctx, req, opts...) } @@ -209,66 +213,101 @@ func (c *networkEndpointGroupsRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of network endpoint groups and sorts them by zone. -func (c *networkEndpointGroupsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/networkEndpointGroups", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *networkEndpointGroupsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointGroupsScopedListPairIterator { + it := &NetworkEndpointGroupsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListNetworkEndpointGroupsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NetworkEndpointGroupAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]NetworkEndpointGroupsScopedListPair, string, error) { + resp := &computepb.NetworkEndpointGroupAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/networkEndpointGroups", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]NetworkEndpointGroupsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, NetworkEndpointGroupsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // AttachNetworkEndpoints attach a list of network endpoints to the specified network endpoint group. -func (c *networkEndpointGroupsRESTClient) AttachNetworkEndpoints(ctx context.Context, req *computepb.AttachNetworkEndpointsNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networkEndpointGroupsRESTClient) AttachNetworkEndpoints(ctx context.Context, req *computepb.AttachNetworkEndpointsNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworkEndpointGroupsAttachEndpointsRequestResource() jsonReq, err := m.Marshal(body) @@ -315,11 +354,15 @@ func (c *networkEndpointGroupsRESTClient) AttachNetworkEndpoints(ctx context.Con unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified network endpoint group. The network endpoints in the NEG and the VM instances they belong to are not terminated when the NEG is deleted. Note that the NEG cannot be deleted if there are backend services referencing it. -func (c *networkEndpointGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networkEndpointGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/networkEndpointGroups/%v", req.GetProject(), req.GetZone(), req.GetNetworkEndpointGroup()) @@ -359,11 +402,15 @@ func (c *networkEndpointGroupsRESTClient) Delete(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DetachNetworkEndpoints detach a list of network endpoints from the specified network endpoint group. -func (c *networkEndpointGroupsRESTClient) DetachNetworkEndpoints(ctx context.Context, req *computepb.DetachNetworkEndpointsNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networkEndpointGroupsRESTClient) DetachNetworkEndpoints(ctx context.Context, req *computepb.DetachNetworkEndpointsNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworkEndpointGroupsDetachEndpointsRequestResource() jsonReq, err := m.Marshal(body) @@ -410,7 +457,11 @@ func (c *networkEndpointGroupsRESTClient) DetachNetworkEndpoints(ctx context.Con unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified network endpoint group. Gets a list of available network endpoint groups by making a list() request. @@ -451,7 +502,7 @@ func (c *networkEndpointGroupsRESTClient) Get(ctx context.Context, req *computep } // Insert creates a network endpoint group in the specified project using the parameters that are included in the request. -func (c *networkEndpointGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networkEndpointGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworkEndpointGroupResource() jsonReq, err := m.Marshal(body) @@ -498,126 +549,185 @@ func (c *networkEndpointGroupsRESTClient) Insert(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of network endpoint groups that are located in the specified project and zone. -func (c *networkEndpointGroupsRESTClient) List(ctx context.Context, req *computepb.ListNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/networkEndpointGroups", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of network endpoint groups that are located in the specified project and zone. +func (c *networkEndpointGroupsRESTClient) List(ctx context.Context, req *computepb.ListNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointGroupIterator { + it := &NetworkEndpointGroupIterator{} + req = proto.Clone(req).(*computepb.ListNetworkEndpointGroupsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NetworkEndpointGroupList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NetworkEndpointGroup, string, error) { + resp := &computepb.NetworkEndpointGroupList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/networkEndpointGroups", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListNetworkEndpoints lists the network endpoints in the specified network endpoint group. -func (c *networkEndpointGroupsRESTClient) ListNetworkEndpoints(ctx context.Context, req *computepb.ListNetworkEndpointsNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupsListNetworkEndpoints, error) { - m := protojson.MarshalOptions{AllowPartial: true} - body := req.GetNetworkEndpointGroupsListEndpointsRequestResource() - jsonReq, err := m.Marshal(body) - if err != nil { - return nil, err - } - - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/networkEndpointGroups/%v/listNetworkEndpoints", req.GetProject(), req.GetZone(), req.GetNetworkEndpointGroup()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *networkEndpointGroupsRESTClient) ListNetworkEndpoints(ctx context.Context, req *computepb.ListNetworkEndpointsNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointWithHealthStatusIterator { + it := &NetworkEndpointWithHealthStatusIterator{} + req = proto.Clone(req).(*computepb.ListNetworkEndpointsNetworkEndpointGroupsRequest) + m := protojson.MarshalOptions{AllowPartial: true, UseProtoNames: false} unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NetworkEndpointGroupsListNetworkEndpoints{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NetworkEndpointWithHealthStatus, string, error) { + resp := &computepb.NetworkEndpointGroupsListNetworkEndpoints{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, "", err + } + + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/networkEndpointGroups/%v/listNetworkEndpoints", req.GetProject(), req.GetZone(), req.GetNetworkEndpointGroup()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -663,3 +773,56 @@ func (c *networkEndpointGroupsRESTClient) TestIamPermissions(ctx context.Context return rsp, unm.Unmarshal(buf, rsp) } + +// NetworkEndpointGroupsScopedListPair is a holder type for string/*computepb.NetworkEndpointGroupsScopedList map entries +type NetworkEndpointGroupsScopedListPair struct { + Key string + Value *computepb.NetworkEndpointGroupsScopedList +} + +// NetworkEndpointGroupsScopedListPairIterator manages a stream of NetworkEndpointGroupsScopedListPair. +type NetworkEndpointGroupsScopedListPairIterator struct { + items []NetworkEndpointGroupsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []NetworkEndpointGroupsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NetworkEndpointGroupsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NetworkEndpointGroupsScopedListPairIterator) Next() (NetworkEndpointGroupsScopedListPair, error) { + var item NetworkEndpointGroupsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NetworkEndpointGroupsScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *NetworkEndpointGroupsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/network_endpoint_groups_client_example_test.go b/compute/apiv1/network_endpoint_groups_client_example_test.go index 5c370298c7a..03e5c0e6052 100644 --- a/compute/apiv1/network_endpoint_groups_client_example_test.go +++ b/compute/apiv1/network_endpoint_groups_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleNetworkEndpointGroupsClient_AggregatedList() { req := &computepb.AggregatedListNetworkEndpointGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNetworkEndpointGroupsClient_AttachNetworkEndpoints() { @@ -160,12 +167,18 @@ func ExampleNetworkEndpointGroupsClient_List() { req := &computepb.ListNetworkEndpointGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNetworkEndpointGroupsClient_ListNetworkEndpoints() { @@ -179,12 +192,18 @@ func ExampleNetworkEndpointGroupsClient_ListNetworkEndpoints() { req := &computepb.ListNetworkEndpointsNetworkEndpointGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListNetworkEndpoints(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListNetworkEndpoints(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNetworkEndpointGroupsClient_TestIamPermissions() { diff --git a/compute/apiv1/networks_client.go b/compute/apiv1/networks_client.go index 3e70954a6ba..108260d6247 100644 --- a/compute/apiv1/networks_client.go +++ b/compute/apiv1/networks_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newNetworksClientHook clientHook @@ -56,17 +59,17 @@ type internalNetworksClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddPeering(context.Context, *computepb.AddPeeringNetworkRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteNetworkRequest, ...gax.CallOption) (*computepb.Operation, error) + AddPeering(context.Context, *computepb.AddPeeringNetworkRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteNetworkRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetNetworkRequest, ...gax.CallOption) (*computepb.Network, error) GetEffectiveFirewalls(context.Context, *computepb.GetEffectiveFirewallsNetworkRequest, ...gax.CallOption) (*computepb.NetworksGetEffectiveFirewallsResponse, error) - Insert(context.Context, *computepb.InsertNetworkRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListNetworksRequest, ...gax.CallOption) (*computepb.NetworkList, error) - ListPeeringRoutes(context.Context, *computepb.ListPeeringRoutesNetworksRequest, ...gax.CallOption) (*computepb.ExchangedPeeringRoutesList, error) - Patch(context.Context, *computepb.PatchNetworkRequest, ...gax.CallOption) (*computepb.Operation, error) - RemovePeering(context.Context, *computepb.RemovePeeringNetworkRequest, ...gax.CallOption) (*computepb.Operation, error) - SwitchToCustomMode(context.Context, *computepb.SwitchToCustomModeNetworkRequest, ...gax.CallOption) (*computepb.Operation, error) - UpdatePeering(context.Context, *computepb.UpdatePeeringNetworkRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertNetworkRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListNetworksRequest, ...gax.CallOption) *NetworkIterator + ListPeeringRoutes(context.Context, *computepb.ListPeeringRoutesNetworksRequest, ...gax.CallOption) *ExchangedPeeringRouteIterator + Patch(context.Context, *computepb.PatchNetworkRequest, ...gax.CallOption) (*Operation, error) + RemovePeering(context.Context, *computepb.RemovePeeringNetworkRequest, ...gax.CallOption) (*Operation, error) + SwitchToCustomMode(context.Context, *computepb.SwitchToCustomModeNetworkRequest, ...gax.CallOption) (*Operation, error) + UpdatePeering(context.Context, *computepb.UpdatePeeringNetworkRequest, ...gax.CallOption) (*Operation, error) } // NetworksClient is a client for interacting with Google Compute Engine API. @@ -104,12 +107,12 @@ func (c *NetworksClient) Connection() *grpc.ClientConn { } // AddPeering adds a peering to the specified network. -func (c *NetworksClient) AddPeering(ctx context.Context, req *computepb.AddPeeringNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworksClient) AddPeering(ctx context.Context, req *computepb.AddPeeringNetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddPeering(ctx, req, opts...) } // Delete deletes the specified network. -func (c *NetworksClient) Delete(ctx context.Context, req *computepb.DeleteNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworksClient) Delete(ctx context.Context, req *computepb.DeleteNetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -124,37 +127,37 @@ func (c *NetworksClient) GetEffectiveFirewalls(ctx context.Context, req *compute } // Insert creates a network in the specified project using the data included in the request. -func (c *NetworksClient) Insert(ctx context.Context, req *computepb.InsertNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworksClient) Insert(ctx context.Context, req *computepb.InsertNetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of networks available to the specified project. -func (c *NetworksClient) List(ctx context.Context, req *computepb.ListNetworksRequest, opts ...gax.CallOption) (*computepb.NetworkList, error) { +func (c *NetworksClient) List(ctx context.Context, req *computepb.ListNetworksRequest, opts ...gax.CallOption) *NetworkIterator { return c.internalClient.List(ctx, req, opts...) } // ListPeeringRoutes lists the peering routes exchanged over peering connection. -func (c *NetworksClient) ListPeeringRoutes(ctx context.Context, req *computepb.ListPeeringRoutesNetworksRequest, opts ...gax.CallOption) (*computepb.ExchangedPeeringRoutesList, error) { +func (c *NetworksClient) ListPeeringRoutes(ctx context.Context, req *computepb.ListPeeringRoutesNetworksRequest, opts ...gax.CallOption) *ExchangedPeeringRouteIterator { return c.internalClient.ListPeeringRoutes(ctx, req, opts...) } // Patch patches the specified network with the data included in the request. Only the following fields can be modified: routingConfig.routingMode. -func (c *NetworksClient) Patch(ctx context.Context, req *computepb.PatchNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworksClient) Patch(ctx context.Context, req *computepb.PatchNetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // RemovePeering removes a peering from the specified network. -func (c *NetworksClient) RemovePeering(ctx context.Context, req *computepb.RemovePeeringNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworksClient) RemovePeering(ctx context.Context, req *computepb.RemovePeeringNetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemovePeering(ctx, req, opts...) } // SwitchToCustomMode switches the network mode from auto subnet mode to custom subnet mode. -func (c *NetworksClient) SwitchToCustomMode(ctx context.Context, req *computepb.SwitchToCustomModeNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworksClient) SwitchToCustomMode(ctx context.Context, req *computepb.SwitchToCustomModeNetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SwitchToCustomMode(ctx, req, opts...) } // UpdatePeering updates the specified network peering with the data included in the request Only the following fields can be modified: NetworkPeering.export_custom_routes, and NetworkPeering.import_custom_routes -func (c *NetworksClient) UpdatePeering(ctx context.Context, req *computepb.UpdatePeeringNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NetworksClient) UpdatePeering(ctx context.Context, req *computepb.UpdatePeeringNetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.UpdatePeering(ctx, req, opts...) } @@ -223,7 +226,7 @@ func (c *networksRESTClient) Connection() *grpc.ClientConn { } // AddPeering adds a peering to the specified network. -func (c *networksRESTClient) AddPeering(ctx context.Context, req *computepb.AddPeeringNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networksRESTClient) AddPeering(ctx context.Context, req *computepb.AddPeeringNetworkRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworksAddPeeringRequestResource() jsonReq, err := m.Marshal(body) @@ -270,11 +273,15 @@ func (c *networksRESTClient) AddPeering(ctx context.Context, req *computepb.AddP unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified network. -func (c *networksRESTClient) Delete(ctx context.Context, req *computepb.DeleteNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networksRESTClient) Delete(ctx context.Context, req *computepb.DeleteNetworkRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networks/%v", req.GetProject(), req.GetNetwork()) @@ -314,7 +321,11 @@ func (c *networksRESTClient) Delete(ctx context.Context, req *computepb.DeleteNe unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified network. Gets a list of available networks by making a list() request. @@ -392,7 +403,7 @@ func (c *networksRESTClient) GetEffectiveFirewalls(ctx context.Context, req *com } // Insert creates a network in the specified project using the data included in the request. -func (c *networksRESTClient) Insert(ctx context.Context, req *computepb.InsertNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networksRESTClient) Insert(ctx context.Context, req *computepb.InsertNetworkRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworkResource() jsonReq, err := m.Marshal(body) @@ -439,132 +450,192 @@ func (c *networksRESTClient) Insert(ctx context.Context, req *computepb.InsertNe unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of networks available to the specified project. -func (c *networksRESTClient) List(ctx context.Context, req *computepb.ListNetworksRequest, opts ...gax.CallOption) (*computepb.NetworkList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networks", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of networks available to the specified project. +func (c *networksRESTClient) List(ctx context.Context, req *computepb.ListNetworksRequest, opts ...gax.CallOption) *NetworkIterator { + it := &NetworkIterator{} + req = proto.Clone(req).(*computepb.ListNetworksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NetworkList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Network, string, error) { + resp := &computepb.NetworkList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networks", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListPeeringRoutes lists the peering routes exchanged over peering connection. -func (c *networksRESTClient) ListPeeringRoutes(ctx context.Context, req *computepb.ListPeeringRoutesNetworksRequest, opts ...gax.CallOption) (*computepb.ExchangedPeeringRoutesList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networks/%v/listPeeringRoutes", req.GetProject(), req.GetNetwork()) - - params := url.Values{} - if req != nil && req.Direction != nil { - params.Add("direction", fmt.Sprintf("%v", req.GetDirection())) - } - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.PeeringName != nil { - params.Add("peeringName", fmt.Sprintf("%v", req.GetPeeringName())) - } - if req != nil && req.Region != nil { - params.Add("region", fmt.Sprintf("%v", req.GetRegion())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *networksRESTClient) ListPeeringRoutes(ctx context.Context, req *computepb.ListPeeringRoutesNetworksRequest, opts ...gax.CallOption) *ExchangedPeeringRouteIterator { + it := &ExchangedPeeringRouteIterator{} + req = proto.Clone(req).(*computepb.ListPeeringRoutesNetworksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ExchangedPeeringRoutesList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.ExchangedPeeringRoute, string, error) { + resp := &computepb.ExchangedPeeringRoutesList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networks/%v/listPeeringRoutes", req.GetProject(), req.GetNetwork()) + + params := url.Values{} + if req != nil && req.Direction != nil { + params.Add("direction", fmt.Sprintf("%v", req.GetDirection())) + } + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.PeeringName != nil { + params.Add("peeringName", fmt.Sprintf("%v", req.GetPeeringName())) + } + if req != nil && req.Region != nil { + params.Add("region", fmt.Sprintf("%v", req.GetRegion())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified network with the data included in the request. Only the following fields can be modified: routingConfig.routingMode. -func (c *networksRESTClient) Patch(ctx context.Context, req *computepb.PatchNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networksRESTClient) Patch(ctx context.Context, req *computepb.PatchNetworkRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworkResource() jsonReq, err := m.Marshal(body) @@ -611,11 +682,15 @@ func (c *networksRESTClient) Patch(ctx context.Context, req *computepb.PatchNetw unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // RemovePeering removes a peering from the specified network. -func (c *networksRESTClient) RemovePeering(ctx context.Context, req *computepb.RemovePeeringNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networksRESTClient) RemovePeering(ctx context.Context, req *computepb.RemovePeeringNetworkRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworksRemovePeeringRequestResource() jsonReq, err := m.Marshal(body) @@ -662,11 +737,15 @@ func (c *networksRESTClient) RemovePeering(ctx context.Context, req *computepb.R unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SwitchToCustomMode switches the network mode from auto subnet mode to custom subnet mode. -func (c *networksRESTClient) SwitchToCustomMode(ctx context.Context, req *computepb.SwitchToCustomModeNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networksRESTClient) SwitchToCustomMode(ctx context.Context, req *computepb.SwitchToCustomModeNetworkRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/networks/%v/switchToCustomMode", req.GetProject(), req.GetNetwork()) @@ -706,11 +785,15 @@ func (c *networksRESTClient) SwitchToCustomMode(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // UpdatePeering updates the specified network peering with the data included in the request Only the following fields can be modified: NetworkPeering.export_custom_routes, and NetworkPeering.import_custom_routes -func (c *networksRESTClient) UpdatePeering(ctx context.Context, req *computepb.UpdatePeeringNetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *networksRESTClient) UpdatePeering(ctx context.Context, req *computepb.UpdatePeeringNetworkRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworksUpdatePeeringRequestResource() jsonReq, err := m.Marshal(body) @@ -757,5 +840,103 @@ func (c *networksRESTClient) UpdatePeering(ctx context.Context, req *computepb.U unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// ExchangedPeeringRouteIterator manages a stream of *computepb.ExchangedPeeringRoute. +type ExchangedPeeringRouteIterator struct { + items []*computepb.ExchangedPeeringRoute + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.ExchangedPeeringRoute, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ExchangedPeeringRouteIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ExchangedPeeringRouteIterator) Next() (*computepb.ExchangedPeeringRoute, error) { + var item *computepb.ExchangedPeeringRoute + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ExchangedPeeringRouteIterator) bufLen() int { + return len(it.items) +} + +func (it *ExchangedPeeringRouteIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// NetworkIterator manages a stream of *computepb.Network. +type NetworkIterator struct { + items []*computepb.Network + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Network, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NetworkIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NetworkIterator) Next() (*computepb.Network, error) { + var item *computepb.Network + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NetworkIterator) bufLen() int { + return len(it.items) +} + +func (it *NetworkIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/networks_client_example_test.go b/compute/apiv1/networks_client_example_test.go index 74578fdc389..d36e990f2d5 100644 --- a/compute/apiv1/networks_client_example_test.go +++ b/compute/apiv1/networks_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -141,12 +142,18 @@ func ExampleNetworksClient_List() { req := &computepb.ListNetworksRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNetworksClient_ListPeeringRoutes() { @@ -160,12 +167,18 @@ func ExampleNetworksClient_ListPeeringRoutes() { req := &computepb.ListPeeringRoutesNetworksRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListPeeringRoutes(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListPeeringRoutes(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNetworksClient_Patch() { diff --git a/compute/apiv1/node_groups_client.go b/compute/apiv1/node_groups_client.go index f60f7f21010..9006c240575 100644 --- a/compute/apiv1/node_groups_client.go +++ b/compute/apiv1/node_groups_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newNodeGroupsClientHook clientHook @@ -58,18 +62,18 @@ type internalNodeGroupsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddNodes(context.Context, *computepb.AddNodesNodeGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - AggregatedList(context.Context, *computepb.AggregatedListNodeGroupsRequest, ...gax.CallOption) (*computepb.NodeGroupAggregatedList, error) - Delete(context.Context, *computepb.DeleteNodeGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - DeleteNodes(context.Context, *computepb.DeleteNodesNodeGroupRequest, ...gax.CallOption) (*computepb.Operation, error) + AddNodes(context.Context, *computepb.AddNodesNodeGroupRequest, ...gax.CallOption) (*Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListNodeGroupsRequest, ...gax.CallOption) *NodeGroupsScopedListPairIterator + Delete(context.Context, *computepb.DeleteNodeGroupRequest, ...gax.CallOption) (*Operation, error) + DeleteNodes(context.Context, *computepb.DeleteNodesNodeGroupRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetNodeGroupRequest, ...gax.CallOption) (*computepb.NodeGroup, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyNodeGroupRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertNodeGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListNodeGroupsRequest, ...gax.CallOption) (*computepb.NodeGroupList, error) - ListNodes(context.Context, *computepb.ListNodesNodeGroupsRequest, ...gax.CallOption) (*computepb.NodeGroupsListNodes, error) - Patch(context.Context, *computepb.PatchNodeGroupRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertNodeGroupRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListNodeGroupsRequest, ...gax.CallOption) *NodeGroupIterator + ListNodes(context.Context, *computepb.ListNodesNodeGroupsRequest, ...gax.CallOption) *NodeGroupNodeIterator + Patch(context.Context, *computepb.PatchNodeGroupRequest, ...gax.CallOption) (*Operation, error) SetIamPolicy(context.Context, *computepb.SetIamPolicyNodeGroupRequest, ...gax.CallOption) (*computepb.Policy, error) - SetNodeTemplate(context.Context, *computepb.SetNodeTemplateNodeGroupRequest, ...gax.CallOption) (*computepb.Operation, error) + SetNodeTemplate(context.Context, *computepb.SetNodeTemplateNodeGroupRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsNodeGroupRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -108,22 +112,22 @@ func (c *NodeGroupsClient) Connection() *grpc.ClientConn { } // AddNodes adds specified number of nodes to the node group. -func (c *NodeGroupsClient) AddNodes(ctx context.Context, req *computepb.AddNodesNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NodeGroupsClient) AddNodes(ctx context.Context, req *computepb.AddNodesNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddNodes(ctx, req, opts...) } // AggregatedList retrieves an aggregated list of node groups. Note: use nodeGroups.listNodes for more details about each group. -func (c *NodeGroupsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeGroupsRequest, opts ...gax.CallOption) (*computepb.NodeGroupAggregatedList, error) { +func (c *NodeGroupsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeGroupsRequest, opts ...gax.CallOption) *NodeGroupsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified NodeGroup resource. -func (c *NodeGroupsClient) Delete(ctx context.Context, req *computepb.DeleteNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NodeGroupsClient) Delete(ctx context.Context, req *computepb.DeleteNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } // DeleteNodes deletes specified nodes from the node group. -func (c *NodeGroupsClient) DeleteNodes(ctx context.Context, req *computepb.DeleteNodesNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NodeGroupsClient) DeleteNodes(ctx context.Context, req *computepb.DeleteNodesNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DeleteNodes(ctx, req, opts...) } @@ -138,22 +142,22 @@ func (c *NodeGroupsClient) GetIamPolicy(ctx context.Context, req *computepb.GetI } // Insert creates a NodeGroup resource in the specified project using the data included in the request. -func (c *NodeGroupsClient) Insert(ctx context.Context, req *computepb.InsertNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NodeGroupsClient) Insert(ctx context.Context, req *computepb.InsertNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of node groups available to the specified project. Note: use nodeGroups.listNodes for more details about each group. -func (c *NodeGroupsClient) List(ctx context.Context, req *computepb.ListNodeGroupsRequest, opts ...gax.CallOption) (*computepb.NodeGroupList, error) { +func (c *NodeGroupsClient) List(ctx context.Context, req *computepb.ListNodeGroupsRequest, opts ...gax.CallOption) *NodeGroupIterator { return c.internalClient.List(ctx, req, opts...) } // ListNodes lists nodes in the node group. -func (c *NodeGroupsClient) ListNodes(ctx context.Context, req *computepb.ListNodesNodeGroupsRequest, opts ...gax.CallOption) (*computepb.NodeGroupsListNodes, error) { +func (c *NodeGroupsClient) ListNodes(ctx context.Context, req *computepb.ListNodesNodeGroupsRequest, opts ...gax.CallOption) *NodeGroupNodeIterator { return c.internalClient.ListNodes(ctx, req, opts...) } // Patch updates the specified node group. -func (c *NodeGroupsClient) Patch(ctx context.Context, req *computepb.PatchNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NodeGroupsClient) Patch(ctx context.Context, req *computepb.PatchNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -163,7 +167,7 @@ func (c *NodeGroupsClient) SetIamPolicy(ctx context.Context, req *computepb.SetI } // SetNodeTemplate updates the node template of the node group. -func (c *NodeGroupsClient) SetNodeTemplate(ctx context.Context, req *computepb.SetNodeTemplateNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NodeGroupsClient) SetNodeTemplate(ctx context.Context, req *computepb.SetNodeTemplateNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetNodeTemplate(ctx, req, opts...) } @@ -237,7 +241,7 @@ func (c *nodeGroupsRESTClient) Connection() *grpc.ClientConn { } // AddNodes adds specified number of nodes to the node group. -func (c *nodeGroupsRESTClient) AddNodes(ctx context.Context, req *computepb.AddNodesNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *nodeGroupsRESTClient) AddNodes(ctx context.Context, req *computepb.AddNodesNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNodeGroupsAddNodesRequestResource() jsonReq, err := m.Marshal(body) @@ -284,70 +288,109 @@ func (c *nodeGroupsRESTClient) AddNodes(ctx context.Context, req *computepb.AddN unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// AggregatedList retrieves an aggregated list of node groups. Note: use nodeGroups.listNodes for more details about each group. -func (c *nodeGroupsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeGroupsRequest, opts ...gax.CallOption) (*computepb.NodeGroupAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/nodeGroups", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// AggregatedList retrieves an aggregated list of node groups. Note: use nodeGroups.listNodes for more details about each group. +func (c *nodeGroupsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeGroupsRequest, opts ...gax.CallOption) *NodeGroupsScopedListPairIterator { + it := &NodeGroupsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListNodeGroupsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NodeGroupAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]NodeGroupsScopedListPair, string, error) { + resp := &computepb.NodeGroupAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/nodeGroups", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]NodeGroupsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, NodeGroupsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified NodeGroup resource. -func (c *nodeGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *nodeGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/nodeGroups/%v", req.GetProject(), req.GetZone(), req.GetNodeGroup()) @@ -387,11 +430,15 @@ func (c *nodeGroupsRESTClient) Delete(ctx context.Context, req *computepb.Delete unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DeleteNodes deletes specified nodes from the node group. -func (c *nodeGroupsRESTClient) DeleteNodes(ctx context.Context, req *computepb.DeleteNodesNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *nodeGroupsRESTClient) DeleteNodes(ctx context.Context, req *computepb.DeleteNodesNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNodeGroupsDeleteNodesRequestResource() jsonReq, err := m.Marshal(body) @@ -438,7 +485,11 @@ func (c *nodeGroupsRESTClient) DeleteNodes(ctx context.Context, req *computepb.D unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified NodeGroup. Get a list of available NodeGroups by making a list() request. Note: the “nodes” field should not be used. Use nodeGroups.listNodes instead. @@ -523,7 +574,7 @@ func (c *nodeGroupsRESTClient) GetIamPolicy(ctx context.Context, req *computepb. } // Insert creates a NodeGroup resource in the specified project using the data included in the request. -func (c *nodeGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *nodeGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNodeGroupResource() jsonReq, err := m.Marshal(body) @@ -573,123 +624,183 @@ func (c *nodeGroupsRESTClient) Insert(ctx context.Context, req *computepb.Insert unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of node groups available to the specified project. Note: use nodeGroups.listNodes for more details about each group. -func (c *nodeGroupsRESTClient) List(ctx context.Context, req *computepb.ListNodeGroupsRequest, opts ...gax.CallOption) (*computepb.NodeGroupList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/nodeGroups", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of node groups available to the specified project. Note: use nodeGroups.listNodes for more details about each group. +func (c *nodeGroupsRESTClient) List(ctx context.Context, req *computepb.ListNodeGroupsRequest, opts ...gax.CallOption) *NodeGroupIterator { + it := &NodeGroupIterator{} + req = proto.Clone(req).(*computepb.ListNodeGroupsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NodeGroupList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NodeGroup, string, error) { + resp := &computepb.NodeGroupList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/nodeGroups", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListNodes lists nodes in the node group. -func (c *nodeGroupsRESTClient) ListNodes(ctx context.Context, req *computepb.ListNodesNodeGroupsRequest, opts ...gax.CallOption) (*computepb.NodeGroupsListNodes, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/nodeGroups/%v/listNodes", req.GetProject(), req.GetZone(), req.GetNodeGroup()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *nodeGroupsRESTClient) ListNodes(ctx context.Context, req *computepb.ListNodesNodeGroupsRequest, opts ...gax.CallOption) *NodeGroupNodeIterator { + it := &NodeGroupNodeIterator{} + req = proto.Clone(req).(*computepb.ListNodesNodeGroupsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NodeGroupsListNodes{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NodeGroupNode, string, error) { + resp := &computepb.NodeGroupsListNodes{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/nodeGroups/%v/listNodes", req.GetProject(), req.GetZone(), req.GetNodeGroup()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates the specified node group. -func (c *nodeGroupsRESTClient) Patch(ctx context.Context, req *computepb.PatchNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *nodeGroupsRESTClient) Patch(ctx context.Context, req *computepb.PatchNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNodeGroupResource() jsonReq, err := m.Marshal(body) @@ -736,7 +847,11 @@ func (c *nodeGroupsRESTClient) Patch(ctx context.Context, req *computepb.PatchNo unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -784,7 +899,7 @@ func (c *nodeGroupsRESTClient) SetIamPolicy(ctx context.Context, req *computepb. } // SetNodeTemplate updates the node template of the node group. -func (c *nodeGroupsRESTClient) SetNodeTemplate(ctx context.Context, req *computepb.SetNodeTemplateNodeGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *nodeGroupsRESTClient) SetNodeTemplate(ctx context.Context, req *computepb.SetNodeTemplateNodeGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNodeGroupsSetNodeTemplateRequestResource() jsonReq, err := m.Marshal(body) @@ -831,7 +946,11 @@ func (c *nodeGroupsRESTClient) SetNodeTemplate(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -877,3 +996,150 @@ func (c *nodeGroupsRESTClient) TestIamPermissions(ctx context.Context, req *comp return rsp, unm.Unmarshal(buf, rsp) } + +// NodeGroupIterator manages a stream of *computepb.NodeGroup. +type NodeGroupIterator struct { + items []*computepb.NodeGroup + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.NodeGroup, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NodeGroupIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NodeGroupIterator) Next() (*computepb.NodeGroup, error) { + var item *computepb.NodeGroup + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NodeGroupIterator) bufLen() int { + return len(it.items) +} + +func (it *NodeGroupIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// NodeGroupNodeIterator manages a stream of *computepb.NodeGroupNode. +type NodeGroupNodeIterator struct { + items []*computepb.NodeGroupNode + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.NodeGroupNode, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NodeGroupNodeIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NodeGroupNodeIterator) Next() (*computepb.NodeGroupNode, error) { + var item *computepb.NodeGroupNode + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NodeGroupNodeIterator) bufLen() int { + return len(it.items) +} + +func (it *NodeGroupNodeIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// NodeGroupsScopedListPair is a holder type for string/*computepb.NodeGroupsScopedList map entries +type NodeGroupsScopedListPair struct { + Key string + Value *computepb.NodeGroupsScopedList +} + +// NodeGroupsScopedListPairIterator manages a stream of NodeGroupsScopedListPair. +type NodeGroupsScopedListPairIterator struct { + items []NodeGroupsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []NodeGroupsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NodeGroupsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NodeGroupsScopedListPairIterator) Next() (NodeGroupsScopedListPair, error) { + var item NodeGroupsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NodeGroupsScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *NodeGroupsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/node_groups_client_example_test.go b/compute/apiv1/node_groups_client_example_test.go index 8cb69f98e69..18e3bd68c4b 100644 --- a/compute/apiv1/node_groups_client_example_test.go +++ b/compute/apiv1/node_groups_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,12 +66,18 @@ func ExampleNodeGroupsClient_AggregatedList() { req := &computepb.AggregatedListNodeGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNodeGroupsClient_Delete() { @@ -179,12 +186,18 @@ func ExampleNodeGroupsClient_List() { req := &computepb.ListNodeGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNodeGroupsClient_ListNodes() { @@ -198,12 +211,18 @@ func ExampleNodeGroupsClient_ListNodes() { req := &computepb.ListNodesNodeGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListNodes(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListNodes(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNodeGroupsClient_Patch() { diff --git a/compute/apiv1/node_templates_client.go b/compute/apiv1/node_templates_client.go index 79c567e95ec..660fbdd22c3 100644 --- a/compute/apiv1/node_templates_client.go +++ b/compute/apiv1/node_templates_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newNodeTemplatesClientHook clientHook @@ -53,12 +57,12 @@ type internalNodeTemplatesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListNodeTemplatesRequest, ...gax.CallOption) (*computepb.NodeTemplateAggregatedList, error) - Delete(context.Context, *computepb.DeleteNodeTemplateRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListNodeTemplatesRequest, ...gax.CallOption) *NodeTemplatesScopedListPairIterator + Delete(context.Context, *computepb.DeleteNodeTemplateRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetNodeTemplateRequest, ...gax.CallOption) (*computepb.NodeTemplate, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyNodeTemplateRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertNodeTemplateRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListNodeTemplatesRequest, ...gax.CallOption) (*computepb.NodeTemplateList, error) + Insert(context.Context, *computepb.InsertNodeTemplateRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListNodeTemplatesRequest, ...gax.CallOption) *NodeTemplateIterator SetIamPolicy(context.Context, *computepb.SetIamPolicyNodeTemplateRequest, ...gax.CallOption) (*computepb.Policy, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsNodeTemplateRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -98,12 +102,12 @@ func (c *NodeTemplatesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of node templates. -func (c *NodeTemplatesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeTemplatesRequest, opts ...gax.CallOption) (*computepb.NodeTemplateAggregatedList, error) { +func (c *NodeTemplatesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeTemplatesRequest, opts ...gax.CallOption) *NodeTemplatesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified NodeTemplate resource. -func (c *NodeTemplatesClient) Delete(ctx context.Context, req *computepb.DeleteNodeTemplateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NodeTemplatesClient) Delete(ctx context.Context, req *computepb.DeleteNodeTemplateRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -118,12 +122,12 @@ func (c *NodeTemplatesClient) GetIamPolicy(ctx context.Context, req *computepb.G } // Insert creates a NodeTemplate resource in the specified project using the data included in the request. -func (c *NodeTemplatesClient) Insert(ctx context.Context, req *computepb.InsertNodeTemplateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *NodeTemplatesClient) Insert(ctx context.Context, req *computepb.InsertNodeTemplateRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of node templates available to the specified project. -func (c *NodeTemplatesClient) List(ctx context.Context, req *computepb.ListNodeTemplatesRequest, opts ...gax.CallOption) (*computepb.NodeTemplateList, error) { +func (c *NodeTemplatesClient) List(ctx context.Context, req *computepb.ListNodeTemplatesRequest, opts ...gax.CallOption) *NodeTemplateIterator { return c.internalClient.List(ctx, req, opts...) } @@ -202,66 +206,101 @@ func (c *nodeTemplatesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of node templates. -func (c *nodeTemplatesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeTemplatesRequest, opts ...gax.CallOption) (*computepb.NodeTemplateAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/nodeTemplates", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *nodeTemplatesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeTemplatesRequest, opts ...gax.CallOption) *NodeTemplatesScopedListPairIterator { + it := &NodeTemplatesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListNodeTemplatesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NodeTemplateAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]NodeTemplatesScopedListPair, string, error) { + resp := &computepb.NodeTemplateAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/nodeTemplates", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]NodeTemplatesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, NodeTemplatesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified NodeTemplate resource. -func (c *nodeTemplatesRESTClient) Delete(ctx context.Context, req *computepb.DeleteNodeTemplateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *nodeTemplatesRESTClient) Delete(ctx context.Context, req *computepb.DeleteNodeTemplateRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/nodeTemplates/%v", req.GetProject(), req.GetRegion(), req.GetNodeTemplate()) @@ -301,7 +340,11 @@ func (c *nodeTemplatesRESTClient) Delete(ctx context.Context, req *computepb.Del unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified node template. Gets a list of available node templates by making a list() request. @@ -386,7 +429,7 @@ func (c *nodeTemplatesRESTClient) GetIamPolicy(ctx context.Context, req *compute } // Insert creates a NodeTemplate resource in the specified project using the data included in the request. -func (c *nodeTemplatesRESTClient) Insert(ctx context.Context, req *computepb.InsertNodeTemplateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *nodeTemplatesRESTClient) Insert(ctx context.Context, req *computepb.InsertNodeTemplateRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNodeTemplateResource() jsonReq, err := m.Marshal(body) @@ -433,63 +476,95 @@ func (c *nodeTemplatesRESTClient) Insert(ctx context.Context, req *computepb.Ins unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of node templates available to the specified project. -func (c *nodeTemplatesRESTClient) List(ctx context.Context, req *computepb.ListNodeTemplatesRequest, opts ...gax.CallOption) (*computepb.NodeTemplateList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/nodeTemplates", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of node templates available to the specified project. +func (c *nodeTemplatesRESTClient) List(ctx context.Context, req *computepb.ListNodeTemplatesRequest, opts ...gax.CallOption) *NodeTemplateIterator { + it := &NodeTemplateIterator{} + req = proto.Clone(req).(*computepb.ListNodeTemplatesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NodeTemplateList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NodeTemplate, string, error) { + resp := &computepb.NodeTemplateList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/nodeTemplates", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -579,3 +654,103 @@ func (c *nodeTemplatesRESTClient) TestIamPermissions(ctx context.Context, req *c return rsp, unm.Unmarshal(buf, rsp) } + +// NodeTemplateIterator manages a stream of *computepb.NodeTemplate. +type NodeTemplateIterator struct { + items []*computepb.NodeTemplate + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.NodeTemplate, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NodeTemplateIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NodeTemplateIterator) Next() (*computepb.NodeTemplate, error) { + var item *computepb.NodeTemplate + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NodeTemplateIterator) bufLen() int { + return len(it.items) +} + +func (it *NodeTemplateIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// NodeTemplatesScopedListPair is a holder type for string/*computepb.NodeTemplatesScopedList map entries +type NodeTemplatesScopedListPair struct { + Key string + Value *computepb.NodeTemplatesScopedList +} + +// NodeTemplatesScopedListPairIterator manages a stream of NodeTemplatesScopedListPair. +type NodeTemplatesScopedListPairIterator struct { + items []NodeTemplatesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []NodeTemplatesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NodeTemplatesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NodeTemplatesScopedListPairIterator) Next() (NodeTemplatesScopedListPair, error) { + var item NodeTemplatesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *NodeTemplatesScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *NodeTemplatesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/node_templates_client_example_test.go b/compute/apiv1/node_templates_client_example_test.go index e589d2ededd..3fb7ee52f61 100644 --- a/compute/apiv1/node_templates_client_example_test.go +++ b/compute/apiv1/node_templates_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleNodeTemplatesClient_AggregatedList() { req := &computepb.AggregatedListNodeTemplatesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNodeTemplatesClient_Delete() { @@ -141,12 +148,18 @@ func ExampleNodeTemplatesClient_List() { req := &computepb.ListNodeTemplatesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNodeTemplatesClient_SetIamPolicy() { diff --git a/compute/apiv1/node_types_client.go b/compute/apiv1/node_types_client.go index 97b80ae2eb2..9d8fde0a346 100644 --- a/compute/apiv1/node_types_client.go +++ b/compute/apiv1/node_types_client.go @@ -20,10 +20,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newNodeTypesClientHook clientHook @@ -47,9 +51,9 @@ type internalNodeTypesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListNodeTypesRequest, ...gax.CallOption) (*computepb.NodeTypeAggregatedList, error) + AggregatedList(context.Context, *computepb.AggregatedListNodeTypesRequest, ...gax.CallOption) *NodeTypesScopedListPairIterator Get(context.Context, *computepb.GetNodeTypeRequest, ...gax.CallOption) (*computepb.NodeType, error) - List(context.Context, *computepb.ListNodeTypesRequest, ...gax.CallOption) (*computepb.NodeTypeList, error) + List(context.Context, *computepb.ListNodeTypesRequest, ...gax.CallOption) *NodeTypeIterator } // NodeTypesClient is a client for interacting with Google Compute Engine API. @@ -87,7 +91,7 @@ func (c *NodeTypesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of node types. -func (c *NodeTypesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeTypesRequest, opts ...gax.CallOption) (*computepb.NodeTypeAggregatedList, error) { +func (c *NodeTypesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeTypesRequest, opts ...gax.CallOption) *NodeTypesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } @@ -97,7 +101,7 @@ func (c *NodeTypesClient) Get(ctx context.Context, req *computepb.GetNodeTypeReq } // List retrieves a list of node types available to the specified project. -func (c *NodeTypesClient) List(ctx context.Context, req *computepb.ListNodeTypesRequest, opts ...gax.CallOption) (*computepb.NodeTypeList, error) { +func (c *NodeTypesClient) List(ctx context.Context, req *computepb.ListNodeTypesRequest, opts ...gax.CallOption) *NodeTypeIterator { return c.internalClient.List(ctx, req, opts...) } @@ -166,62 +170,97 @@ func (c *nodeTypesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of node types. -func (c *nodeTypesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeTypesRequest, opts ...gax.CallOption) (*computepb.NodeTypeAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/nodeTypes", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +func (c *nodeTypesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListNodeTypesRequest, opts ...gax.CallOption) *NodeTypesScopedListPairIterator { + it := &NodeTypesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListNodeTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]NodeTypesScopedListPair, string, error) { + resp := &computepb.NodeTypeAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/nodeTypes", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]NodeTypesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, NodeTypesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NodeTypeAggregatedList{} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - return rsp, unm.Unmarshal(buf, rsp) + return it } // Get returns the specified node type. Gets a list of available node types by making a list() request. @@ -262,57 +301,185 @@ func (c *nodeTypesRESTClient) Get(ctx context.Context, req *computepb.GetNodeTyp } // List retrieves a list of node types available to the specified project. -func (c *nodeTypesRESTClient) List(ctx context.Context, req *computepb.ListNodeTypesRequest, opts ...gax.CallOption) (*computepb.NodeTypeList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/nodeTypes", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *nodeTypesRESTClient) List(ctx context.Context, req *computepb.ListNodeTypesRequest, opts ...gax.CallOption) *NodeTypeIterator { + it := &NodeTypeIterator{} + req = proto.Clone(req).(*computepb.ListNodeTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NodeType, string, error) { + resp := &computepb.NodeTypeList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/nodeTypes", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// NodeTypeIterator manages a stream of *computepb.NodeType. +type NodeTypeIterator struct { + items []*computepb.NodeType + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.NodeType, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NodeTypeIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NodeTypeIterator) Next() (*computepb.NodeType, error) { + var item *computepb.NodeType + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +func (it *NodeTypeIterator) bufLen() int { + return len(it.items) +} + +func (it *NodeTypeIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// NodeTypesScopedListPair is a holder type for string/*computepb.NodeTypesScopedList map entries +type NodeTypesScopedListPair struct { + Key string + Value *computepb.NodeTypesScopedList +} + +// NodeTypesScopedListPairIterator manages a stream of NodeTypesScopedListPair. +type NodeTypesScopedListPairIterator struct { + items []NodeTypesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []NodeTypesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NodeTypesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NodeTypesScopedListPairIterator) Next() (NodeTypesScopedListPair, error) { + var item NodeTypesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NodeTypeList{} +func (it *NodeTypesScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *NodeTypesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/node_types_client_example_test.go b/compute/apiv1/node_types_client_example_test.go index 9f184468eac..c47eb6c150e 100644 --- a/compute/apiv1/node_types_client_example_test.go +++ b/compute/apiv1/node_types_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleNodeTypesClient_AggregatedList() { req := &computepb.AggregatedListNodeTypesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleNodeTypesClient_Get() { @@ -84,10 +91,16 @@ func ExampleNodeTypesClient_List() { req := &computepb.ListNodeTypesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/packet_mirrorings_client.go b/compute/apiv1/packet_mirrorings_client.go index 7d9ce24642d..b22eeea1c50 100644 --- a/compute/apiv1/packet_mirrorings_client.go +++ b/compute/apiv1/packet_mirrorings_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newPacketMirroringsClientHook clientHook @@ -52,12 +56,12 @@ type internalPacketMirroringsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListPacketMirroringsRequest, ...gax.CallOption) (*computepb.PacketMirroringAggregatedList, error) - Delete(context.Context, *computepb.DeletePacketMirroringRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListPacketMirroringsRequest, ...gax.CallOption) *PacketMirroringsScopedListPairIterator + Delete(context.Context, *computepb.DeletePacketMirroringRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetPacketMirroringRequest, ...gax.CallOption) (*computepb.PacketMirroring, error) - Insert(context.Context, *computepb.InsertPacketMirroringRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListPacketMirroringsRequest, ...gax.CallOption) (*computepb.PacketMirroringList, error) - Patch(context.Context, *computepb.PatchPacketMirroringRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertPacketMirroringRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListPacketMirroringsRequest, ...gax.CallOption) *PacketMirroringIterator + Patch(context.Context, *computepb.PatchPacketMirroringRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsPacketMirroringRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -96,12 +100,12 @@ func (c *PacketMirroringsClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of packetMirrorings. -func (c *PacketMirroringsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListPacketMirroringsRequest, opts ...gax.CallOption) (*computepb.PacketMirroringAggregatedList, error) { +func (c *PacketMirroringsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListPacketMirroringsRequest, opts ...gax.CallOption) *PacketMirroringsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified PacketMirroring resource. -func (c *PacketMirroringsClient) Delete(ctx context.Context, req *computepb.DeletePacketMirroringRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *PacketMirroringsClient) Delete(ctx context.Context, req *computepb.DeletePacketMirroringRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -111,17 +115,17 @@ func (c *PacketMirroringsClient) Get(ctx context.Context, req *computepb.GetPack } // Insert creates a PacketMirroring resource in the specified project and region using the data included in the request. -func (c *PacketMirroringsClient) Insert(ctx context.Context, req *computepb.InsertPacketMirroringRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *PacketMirroringsClient) Insert(ctx context.Context, req *computepb.InsertPacketMirroringRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of PacketMirroring resources available to the specified project and region. -func (c *PacketMirroringsClient) List(ctx context.Context, req *computepb.ListPacketMirroringsRequest, opts ...gax.CallOption) (*computepb.PacketMirroringList, error) { +func (c *PacketMirroringsClient) List(ctx context.Context, req *computepb.ListPacketMirroringsRequest, opts ...gax.CallOption) *PacketMirroringIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified PacketMirroring resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *PacketMirroringsClient) Patch(ctx context.Context, req *computepb.PatchPacketMirroringRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *PacketMirroringsClient) Patch(ctx context.Context, req *computepb.PatchPacketMirroringRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -195,66 +199,101 @@ func (c *packetMirroringsRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of packetMirrorings. -func (c *packetMirroringsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListPacketMirroringsRequest, opts ...gax.CallOption) (*computepb.PacketMirroringAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/packetMirrorings", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *packetMirroringsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListPacketMirroringsRequest, opts ...gax.CallOption) *PacketMirroringsScopedListPairIterator { + it := &PacketMirroringsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListPacketMirroringsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.PacketMirroringAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]PacketMirroringsScopedListPair, string, error) { + resp := &computepb.PacketMirroringAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/packetMirrorings", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]PacketMirroringsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, PacketMirroringsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified PacketMirroring resource. -func (c *packetMirroringsRESTClient) Delete(ctx context.Context, req *computepb.DeletePacketMirroringRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *packetMirroringsRESTClient) Delete(ctx context.Context, req *computepb.DeletePacketMirroringRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/packetMirrorings/%v", req.GetProject(), req.GetRegion(), req.GetPacketMirroring()) @@ -294,7 +333,11 @@ func (c *packetMirroringsRESTClient) Delete(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified PacketMirroring resource. @@ -335,7 +378,7 @@ func (c *packetMirroringsRESTClient) Get(ctx context.Context, req *computepb.Get } // Insert creates a PacketMirroring resource in the specified project and region using the data included in the request. -func (c *packetMirroringsRESTClient) Insert(ctx context.Context, req *computepb.InsertPacketMirroringRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *packetMirroringsRESTClient) Insert(ctx context.Context, req *computepb.InsertPacketMirroringRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetPacketMirroringResource() jsonReq, err := m.Marshal(body) @@ -382,67 +425,99 @@ func (c *packetMirroringsRESTClient) Insert(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of PacketMirroring resources available to the specified project and region. -func (c *packetMirroringsRESTClient) List(ctx context.Context, req *computepb.ListPacketMirroringsRequest, opts ...gax.CallOption) (*computepb.PacketMirroringList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/packetMirrorings", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of PacketMirroring resources available to the specified project and region. +func (c *packetMirroringsRESTClient) List(ctx context.Context, req *computepb.ListPacketMirroringsRequest, opts ...gax.CallOption) *PacketMirroringIterator { + it := &PacketMirroringIterator{} + req = proto.Clone(req).(*computepb.ListPacketMirroringsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.PacketMirroringList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.PacketMirroring, string, error) { + resp := &computepb.PacketMirroringList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/packetMirrorings", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified PacketMirroring resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *packetMirroringsRESTClient) Patch(ctx context.Context, req *computepb.PatchPacketMirroringRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *packetMirroringsRESTClient) Patch(ctx context.Context, req *computepb.PatchPacketMirroringRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetPacketMirroringResource() jsonReq, err := m.Marshal(body) @@ -489,7 +564,11 @@ func (c *packetMirroringsRESTClient) Patch(ctx context.Context, req *computepb.P unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -535,3 +614,103 @@ func (c *packetMirroringsRESTClient) TestIamPermissions(ctx context.Context, req return rsp, unm.Unmarshal(buf, rsp) } + +// PacketMirroringIterator manages a stream of *computepb.PacketMirroring. +type PacketMirroringIterator struct { + items []*computepb.PacketMirroring + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.PacketMirroring, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *PacketMirroringIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *PacketMirroringIterator) Next() (*computepb.PacketMirroring, error) { + var item *computepb.PacketMirroring + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *PacketMirroringIterator) bufLen() int { + return len(it.items) +} + +func (it *PacketMirroringIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// PacketMirroringsScopedListPair is a holder type for string/*computepb.PacketMirroringsScopedList map entries +type PacketMirroringsScopedListPair struct { + Key string + Value *computepb.PacketMirroringsScopedList +} + +// PacketMirroringsScopedListPairIterator manages a stream of PacketMirroringsScopedListPair. +type PacketMirroringsScopedListPairIterator struct { + items []PacketMirroringsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []PacketMirroringsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *PacketMirroringsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *PacketMirroringsScopedListPairIterator) Next() (PacketMirroringsScopedListPair, error) { + var item PacketMirroringsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *PacketMirroringsScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *PacketMirroringsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/packet_mirrorings_client_example_test.go b/compute/apiv1/packet_mirrorings_client_example_test.go index 6ce5c37025e..3df14b1acb4 100644 --- a/compute/apiv1/packet_mirrorings_client_example_test.go +++ b/compute/apiv1/packet_mirrorings_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExamplePacketMirroringsClient_AggregatedList() { req := &computepb.AggregatedListPacketMirroringsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExamplePacketMirroringsClient_Delete() { @@ -122,12 +129,18 @@ func ExamplePacketMirroringsClient_List() { req := &computepb.ListPacketMirroringsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExamplePacketMirroringsClient_Patch() { diff --git a/compute/apiv1/projects_client.go b/compute/apiv1/projects_client.go index 58bdd7ddc12..cff792e7ccd 100644 --- a/compute/apiv1/projects_client.go +++ b/compute/apiv1/projects_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newProjectsClientHook clientHook @@ -58,19 +61,19 @@ type internalProjectsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - DisableXpnHost(context.Context, *computepb.DisableXpnHostProjectRequest, ...gax.CallOption) (*computepb.Operation, error) - DisableXpnResource(context.Context, *computepb.DisableXpnResourceProjectRequest, ...gax.CallOption) (*computepb.Operation, error) - EnableXpnHost(context.Context, *computepb.EnableXpnHostProjectRequest, ...gax.CallOption) (*computepb.Operation, error) - EnableXpnResource(context.Context, *computepb.EnableXpnResourceProjectRequest, ...gax.CallOption) (*computepb.Operation, error) + DisableXpnHost(context.Context, *computepb.DisableXpnHostProjectRequest, ...gax.CallOption) (*Operation, error) + DisableXpnResource(context.Context, *computepb.DisableXpnResourceProjectRequest, ...gax.CallOption) (*Operation, error) + EnableXpnHost(context.Context, *computepb.EnableXpnHostProjectRequest, ...gax.CallOption) (*Operation, error) + EnableXpnResource(context.Context, *computepb.EnableXpnResourceProjectRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetProjectRequest, ...gax.CallOption) (*computepb.Project, error) GetXpnHost(context.Context, *computepb.GetXpnHostProjectRequest, ...gax.CallOption) (*computepb.Project, error) - GetXpnResources(context.Context, *computepb.GetXpnResourcesProjectsRequest, ...gax.CallOption) (*computepb.ProjectsGetXpnResources, error) - ListXpnHosts(context.Context, *computepb.ListXpnHostsProjectsRequest, ...gax.CallOption) (*computepb.XpnHostList, error) - MoveDisk(context.Context, *computepb.MoveDiskProjectRequest, ...gax.CallOption) (*computepb.Operation, error) - MoveInstance(context.Context, *computepb.MoveInstanceProjectRequest, ...gax.CallOption) (*computepb.Operation, error) - SetCommonInstanceMetadata(context.Context, *computepb.SetCommonInstanceMetadataProjectRequest, ...gax.CallOption) (*computepb.Operation, error) - SetDefaultNetworkTier(context.Context, *computepb.SetDefaultNetworkTierProjectRequest, ...gax.CallOption) (*computepb.Operation, error) - SetUsageExportBucket(context.Context, *computepb.SetUsageExportBucketProjectRequest, ...gax.CallOption) (*computepb.Operation, error) + GetXpnResources(context.Context, *computepb.GetXpnResourcesProjectsRequest, ...gax.CallOption) *XpnResourceIdIterator + ListXpnHosts(context.Context, *computepb.ListXpnHostsProjectsRequest, ...gax.CallOption) *ProjectIterator + MoveDisk(context.Context, *computepb.MoveDiskProjectRequest, ...gax.CallOption) (*Operation, error) + MoveInstance(context.Context, *computepb.MoveInstanceProjectRequest, ...gax.CallOption) (*Operation, error) + SetCommonInstanceMetadata(context.Context, *computepb.SetCommonInstanceMetadataProjectRequest, ...gax.CallOption) (*Operation, error) + SetDefaultNetworkTier(context.Context, *computepb.SetDefaultNetworkTierProjectRequest, ...gax.CallOption) (*Operation, error) + SetUsageExportBucket(context.Context, *computepb.SetUsageExportBucketProjectRequest, ...gax.CallOption) (*Operation, error) } // ProjectsClient is a client for interacting with Google Compute Engine API. @@ -108,22 +111,22 @@ func (c *ProjectsClient) Connection() *grpc.ClientConn { } // DisableXpnHost disable this project as a shared VPC host project. -func (c *ProjectsClient) DisableXpnHost(ctx context.Context, req *computepb.DisableXpnHostProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ProjectsClient) DisableXpnHost(ctx context.Context, req *computepb.DisableXpnHostProjectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DisableXpnHost(ctx, req, opts...) } // DisableXpnResource disable a service resource (also known as service project) associated with this host project. -func (c *ProjectsClient) DisableXpnResource(ctx context.Context, req *computepb.DisableXpnResourceProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ProjectsClient) DisableXpnResource(ctx context.Context, req *computepb.DisableXpnResourceProjectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DisableXpnResource(ctx, req, opts...) } // EnableXpnHost enable this project as a shared VPC host project. -func (c *ProjectsClient) EnableXpnHost(ctx context.Context, req *computepb.EnableXpnHostProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ProjectsClient) EnableXpnHost(ctx context.Context, req *computepb.EnableXpnHostProjectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.EnableXpnHost(ctx, req, opts...) } // EnableXpnResource enable service resource (a.k.a service project) for a host project, so that subnets in the host project can be used by instances in the service project. -func (c *ProjectsClient) EnableXpnResource(ctx context.Context, req *computepb.EnableXpnResourceProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ProjectsClient) EnableXpnResource(ctx context.Context, req *computepb.EnableXpnResourceProjectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.EnableXpnResource(ctx, req, opts...) } @@ -138,37 +141,37 @@ func (c *ProjectsClient) GetXpnHost(ctx context.Context, req *computepb.GetXpnHo } // GetXpnResources gets service resources (a.k.a service project) associated with this host project. -func (c *ProjectsClient) GetXpnResources(ctx context.Context, req *computepb.GetXpnResourcesProjectsRequest, opts ...gax.CallOption) (*computepb.ProjectsGetXpnResources, error) { +func (c *ProjectsClient) GetXpnResources(ctx context.Context, req *computepb.GetXpnResourcesProjectsRequest, opts ...gax.CallOption) *XpnResourceIdIterator { return c.internalClient.GetXpnResources(ctx, req, opts...) } // ListXpnHosts lists all shared VPC host projects visible to the user in an organization. -func (c *ProjectsClient) ListXpnHosts(ctx context.Context, req *computepb.ListXpnHostsProjectsRequest, opts ...gax.CallOption) (*computepb.XpnHostList, error) { +func (c *ProjectsClient) ListXpnHosts(ctx context.Context, req *computepb.ListXpnHostsProjectsRequest, opts ...gax.CallOption) *ProjectIterator { return c.internalClient.ListXpnHosts(ctx, req, opts...) } // MoveDisk moves a persistent disk from one zone to another. -func (c *ProjectsClient) MoveDisk(ctx context.Context, req *computepb.MoveDiskProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ProjectsClient) MoveDisk(ctx context.Context, req *computepb.MoveDiskProjectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.MoveDisk(ctx, req, opts...) } // MoveInstance moves an instance and its attached persistent disks from one zone to another. -func (c *ProjectsClient) MoveInstance(ctx context.Context, req *computepb.MoveInstanceProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ProjectsClient) MoveInstance(ctx context.Context, req *computepb.MoveInstanceProjectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.MoveInstance(ctx, req, opts...) } // SetCommonInstanceMetadata sets metadata common to all instances within the specified project using the data included in the request. -func (c *ProjectsClient) SetCommonInstanceMetadata(ctx context.Context, req *computepb.SetCommonInstanceMetadataProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ProjectsClient) SetCommonInstanceMetadata(ctx context.Context, req *computepb.SetCommonInstanceMetadataProjectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetCommonInstanceMetadata(ctx, req, opts...) } // SetDefaultNetworkTier sets the default network tier of the project. The default network tier is used when an address/forwardingRule/instance is created without specifying the network tier field. -func (c *ProjectsClient) SetDefaultNetworkTier(ctx context.Context, req *computepb.SetDefaultNetworkTierProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ProjectsClient) SetDefaultNetworkTier(ctx context.Context, req *computepb.SetDefaultNetworkTierProjectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetDefaultNetworkTier(ctx, req, opts...) } // SetUsageExportBucket enables the usage export feature and sets the usage export bucket where reports are stored. If you provide an empty request body using this method, the usage export feature will be disabled. -func (c *ProjectsClient) SetUsageExportBucket(ctx context.Context, req *computepb.SetUsageExportBucketProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ProjectsClient) SetUsageExportBucket(ctx context.Context, req *computepb.SetUsageExportBucketProjectRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetUsageExportBucket(ctx, req, opts...) } @@ -237,7 +240,7 @@ func (c *projectsRESTClient) Connection() *grpc.ClientConn { } // DisableXpnHost disable this project as a shared VPC host project. -func (c *projectsRESTClient) DisableXpnHost(ctx context.Context, req *computepb.DisableXpnHostProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *projectsRESTClient) DisableXpnHost(ctx context.Context, req *computepb.DisableXpnHostProjectRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/disableXpnHost", req.GetProject()) @@ -277,11 +280,15 @@ func (c *projectsRESTClient) DisableXpnHost(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DisableXpnResource disable a service resource (also known as service project) associated with this host project. -func (c *projectsRESTClient) DisableXpnResource(ctx context.Context, req *computepb.DisableXpnResourceProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *projectsRESTClient) DisableXpnResource(ctx context.Context, req *computepb.DisableXpnResourceProjectRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetProjectsDisableXpnResourceRequestResource() jsonReq, err := m.Marshal(body) @@ -328,11 +335,15 @@ func (c *projectsRESTClient) DisableXpnResource(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // EnableXpnHost enable this project as a shared VPC host project. -func (c *projectsRESTClient) EnableXpnHost(ctx context.Context, req *computepb.EnableXpnHostProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *projectsRESTClient) EnableXpnHost(ctx context.Context, req *computepb.EnableXpnHostProjectRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/enableXpnHost", req.GetProject()) @@ -372,11 +383,15 @@ func (c *projectsRESTClient) EnableXpnHost(ctx context.Context, req *computepb.E unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // EnableXpnResource enable service resource (a.k.a service project) for a host project, so that subnets in the host project can be used by instances in the service project. -func (c *projectsRESTClient) EnableXpnResource(ctx context.Context, req *computepb.EnableXpnResourceProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *projectsRESTClient) EnableXpnResource(ctx context.Context, req *computepb.EnableXpnResourceProjectRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetProjectsEnableXpnResourceRequestResource() jsonReq, err := m.Marshal(body) @@ -423,7 +438,11 @@ func (c *projectsRESTClient) EnableXpnResource(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified Project resource. @@ -501,126 +520,181 @@ func (c *projectsRESTClient) GetXpnHost(ctx context.Context, req *computepb.GetX } // GetXpnResources gets service resources (a.k.a service project) associated with this host project. -func (c *projectsRESTClient) GetXpnResources(ctx context.Context, req *computepb.GetXpnResourcesProjectsRequest, opts ...gax.CallOption) (*computepb.ProjectsGetXpnResources, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/getXpnResources", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *projectsRESTClient) GetXpnResources(ctx context.Context, req *computepb.GetXpnResourcesProjectsRequest, opts ...gax.CallOption) *XpnResourceIdIterator { + it := &XpnResourceIdIterator{} + req = proto.Clone(req).(*computepb.GetXpnResourcesProjectsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ProjectsGetXpnResources{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.XpnResourceId, string, error) { + resp := &computepb.ProjectsGetXpnResources{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/getXpnResources", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetResources(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListXpnHosts lists all shared VPC host projects visible to the user in an organization. -func (c *projectsRESTClient) ListXpnHosts(ctx context.Context, req *computepb.ListXpnHostsProjectsRequest, opts ...gax.CallOption) (*computepb.XpnHostList, error) { - m := protojson.MarshalOptions{AllowPartial: true} - body := req.GetProjectsListXpnHostsRequestResource() - jsonReq, err := m.Marshal(body) - if err != nil { - return nil, err - } - - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/listXpnHosts", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *projectsRESTClient) ListXpnHosts(ctx context.Context, req *computepb.ListXpnHostsProjectsRequest, opts ...gax.CallOption) *ProjectIterator { + it := &ProjectIterator{} + req = proto.Clone(req).(*computepb.ListXpnHostsProjectsRequest) + m := protojson.MarshalOptions{AllowPartial: true, UseProtoNames: false} unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.XpnHostList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Project, string, error) { + resp := &computepb.XpnHostList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, "", err + } + + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/listXpnHosts", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // MoveDisk moves a persistent disk from one zone to another. -func (c *projectsRESTClient) MoveDisk(ctx context.Context, req *computepb.MoveDiskProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *projectsRESTClient) MoveDisk(ctx context.Context, req *computepb.MoveDiskProjectRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetDiskMoveRequestResource() jsonReq, err := m.Marshal(body) @@ -667,11 +741,15 @@ func (c *projectsRESTClient) MoveDisk(ctx context.Context, req *computepb.MoveDi unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // MoveInstance moves an instance and its attached persistent disks from one zone to another. -func (c *projectsRESTClient) MoveInstance(ctx context.Context, req *computepb.MoveInstanceProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *projectsRESTClient) MoveInstance(ctx context.Context, req *computepb.MoveInstanceProjectRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceMoveRequestResource() jsonReq, err := m.Marshal(body) @@ -718,11 +796,15 @@ func (c *projectsRESTClient) MoveInstance(ctx context.Context, req *computepb.Mo unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetCommonInstanceMetadata sets metadata common to all instances within the specified project using the data included in the request. -func (c *projectsRESTClient) SetCommonInstanceMetadata(ctx context.Context, req *computepb.SetCommonInstanceMetadataProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *projectsRESTClient) SetCommonInstanceMetadata(ctx context.Context, req *computepb.SetCommonInstanceMetadataProjectRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetMetadataResource() jsonReq, err := m.Marshal(body) @@ -769,11 +851,15 @@ func (c *projectsRESTClient) SetCommonInstanceMetadata(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetDefaultNetworkTier sets the default network tier of the project. The default network tier is used when an address/forwardingRule/instance is created without specifying the network tier field. -func (c *projectsRESTClient) SetDefaultNetworkTier(ctx context.Context, req *computepb.SetDefaultNetworkTierProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *projectsRESTClient) SetDefaultNetworkTier(ctx context.Context, req *computepb.SetDefaultNetworkTierProjectRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetProjectsSetDefaultNetworkTierRequestResource() jsonReq, err := m.Marshal(body) @@ -820,11 +906,15 @@ func (c *projectsRESTClient) SetDefaultNetworkTier(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetUsageExportBucket enables the usage export feature and sets the usage export bucket where reports are stored. If you provide an empty request body using this method, the usage export feature will be disabled. -func (c *projectsRESTClient) SetUsageExportBucket(ctx context.Context, req *computepb.SetUsageExportBucketProjectRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *projectsRESTClient) SetUsageExportBucket(ctx context.Context, req *computepb.SetUsageExportBucketProjectRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUsageExportLocationResource() jsonReq, err := m.Marshal(body) @@ -871,5 +961,103 @@ func (c *projectsRESTClient) SetUsageExportBucket(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// ProjectIterator manages a stream of *computepb.Project. +type ProjectIterator struct { + items []*computepb.Project + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Project, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ProjectIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ProjectIterator) Next() (*computepb.Project, error) { + var item *computepb.Project + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ProjectIterator) bufLen() int { + return len(it.items) +} + +func (it *ProjectIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// XpnResourceIdIterator manages a stream of *computepb.XpnResourceId. +type XpnResourceIdIterator struct { + items []*computepb.XpnResourceId + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.XpnResourceId, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *XpnResourceIdIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *XpnResourceIdIterator) Next() (*computepb.XpnResourceId, error) { + var item *computepb.XpnResourceId + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *XpnResourceIdIterator) bufLen() int { + return len(it.items) +} + +func (it *XpnResourceIdIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/projects_client_example_test.go b/compute/apiv1/projects_client_example_test.go index 7ef81b62889..9f920a9ed5b 100644 --- a/compute/apiv1/projects_client_example_test.go +++ b/compute/apiv1/projects_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -160,12 +161,18 @@ func ExampleProjectsClient_GetXpnResources() { req := &computepb.GetXpnResourcesProjectsRequest{ // TODO: Fill request struct fields. } - resp, err := c.GetXpnResources(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.GetXpnResources(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleProjectsClient_ListXpnHosts() { @@ -179,12 +186,18 @@ func ExampleProjectsClient_ListXpnHosts() { req := &computepb.ListXpnHostsProjectsRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListXpnHosts(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListXpnHosts(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleProjectsClient_MoveDisk() { diff --git a/compute/apiv1/public_advertised_prefixes_client.go b/compute/apiv1/public_advertised_prefixes_client.go index 5fdcbf3a988..3bb4775871e 100644 --- a/compute/apiv1/public_advertised_prefixes_client.go +++ b/compute/apiv1/public_advertised_prefixes_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newPublicAdvertisedPrefixesClientHook clientHook @@ -50,11 +53,11 @@ type internalPublicAdvertisedPrefixesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeletePublicAdvertisedPrefixeRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeletePublicAdvertisedPrefixeRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetPublicAdvertisedPrefixeRequest, ...gax.CallOption) (*computepb.PublicAdvertisedPrefix, error) - Insert(context.Context, *computepb.InsertPublicAdvertisedPrefixeRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListPublicAdvertisedPrefixesRequest, ...gax.CallOption) (*computepb.PublicAdvertisedPrefixList, error) - Patch(context.Context, *computepb.PatchPublicAdvertisedPrefixeRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertPublicAdvertisedPrefixeRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListPublicAdvertisedPrefixesRequest, ...gax.CallOption) *PublicAdvertisedPrefixIterator + Patch(context.Context, *computepb.PatchPublicAdvertisedPrefixeRequest, ...gax.CallOption) (*Operation, error) } // PublicAdvertisedPrefixesClient is a client for interacting with Google Compute Engine API. @@ -92,7 +95,7 @@ func (c *PublicAdvertisedPrefixesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified PublicAdvertisedPrefix -func (c *PublicAdvertisedPrefixesClient) Delete(ctx context.Context, req *computepb.DeletePublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *PublicAdvertisedPrefixesClient) Delete(ctx context.Context, req *computepb.DeletePublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -102,17 +105,17 @@ func (c *PublicAdvertisedPrefixesClient) Get(ctx context.Context, req *computepb } // Insert creates a PublicAdvertisedPrefix in the specified project using the parameters that are included in the request. -func (c *PublicAdvertisedPrefixesClient) Insert(ctx context.Context, req *computepb.InsertPublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *PublicAdvertisedPrefixesClient) Insert(ctx context.Context, req *computepb.InsertPublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List lists the PublicAdvertisedPrefixes for a project. -func (c *PublicAdvertisedPrefixesClient) List(ctx context.Context, req *computepb.ListPublicAdvertisedPrefixesRequest, opts ...gax.CallOption) (*computepb.PublicAdvertisedPrefixList, error) { +func (c *PublicAdvertisedPrefixesClient) List(ctx context.Context, req *computepb.ListPublicAdvertisedPrefixesRequest, opts ...gax.CallOption) *PublicAdvertisedPrefixIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified Router resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *PublicAdvertisedPrefixesClient) Patch(ctx context.Context, req *computepb.PatchPublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *PublicAdvertisedPrefixesClient) Patch(ctx context.Context, req *computepb.PatchPublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -181,7 +184,7 @@ func (c *publicAdvertisedPrefixesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified PublicAdvertisedPrefix -func (c *publicAdvertisedPrefixesRESTClient) Delete(ctx context.Context, req *computepb.DeletePublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *publicAdvertisedPrefixesRESTClient) Delete(ctx context.Context, req *computepb.DeletePublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/publicAdvertisedPrefixes/%v", req.GetProject(), req.GetPublicAdvertisedPrefix()) @@ -221,7 +224,11 @@ func (c *publicAdvertisedPrefixesRESTClient) Delete(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified PublicAdvertisedPrefix resource. @@ -262,7 +269,7 @@ func (c *publicAdvertisedPrefixesRESTClient) Get(ctx context.Context, req *compu } // Insert creates a PublicAdvertisedPrefix in the specified project using the parameters that are included in the request. -func (c *publicAdvertisedPrefixesRESTClient) Insert(ctx context.Context, req *computepb.InsertPublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *publicAdvertisedPrefixesRESTClient) Insert(ctx context.Context, req *computepb.InsertPublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetPublicAdvertisedPrefixResource() jsonReq, err := m.Marshal(body) @@ -309,67 +316,99 @@ func (c *publicAdvertisedPrefixesRESTClient) Insert(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List lists the PublicAdvertisedPrefixes for a project. -func (c *publicAdvertisedPrefixesRESTClient) List(ctx context.Context, req *computepb.ListPublicAdvertisedPrefixesRequest, opts ...gax.CallOption) (*computepb.PublicAdvertisedPrefixList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/publicAdvertisedPrefixes", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List lists the PublicAdvertisedPrefixes for a project. +func (c *publicAdvertisedPrefixesRESTClient) List(ctx context.Context, req *computepb.ListPublicAdvertisedPrefixesRequest, opts ...gax.CallOption) *PublicAdvertisedPrefixIterator { + it := &PublicAdvertisedPrefixIterator{} + req = proto.Clone(req).(*computepb.ListPublicAdvertisedPrefixesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.PublicAdvertisedPrefixList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.PublicAdvertisedPrefix, string, error) { + resp := &computepb.PublicAdvertisedPrefixList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/publicAdvertisedPrefixes", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified Router resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *publicAdvertisedPrefixesRESTClient) Patch(ctx context.Context, req *computepb.PatchPublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *publicAdvertisedPrefixesRESTClient) Patch(ctx context.Context, req *computepb.PatchPublicAdvertisedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetPublicAdvertisedPrefixResource() jsonReq, err := m.Marshal(body) @@ -416,5 +455,56 @@ func (c *publicAdvertisedPrefixesRESTClient) Patch(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// PublicAdvertisedPrefixIterator manages a stream of *computepb.PublicAdvertisedPrefix. +type PublicAdvertisedPrefixIterator struct { + items []*computepb.PublicAdvertisedPrefix + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.PublicAdvertisedPrefix, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *PublicAdvertisedPrefixIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *PublicAdvertisedPrefixIterator) Next() (*computepb.PublicAdvertisedPrefix, error) { + var item *computepb.PublicAdvertisedPrefix + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *PublicAdvertisedPrefixIterator) bufLen() int { + return len(it.items) +} + +func (it *PublicAdvertisedPrefixIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/public_advertised_prefixes_client_example_test.go b/compute/apiv1/public_advertised_prefixes_client_example_test.go index 157318c0c4d..c547c740d93 100644 --- a/compute/apiv1/public_advertised_prefixes_client_example_test.go +++ b/compute/apiv1/public_advertised_prefixes_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExamplePublicAdvertisedPrefixesClient_List() { req := &computepb.ListPublicAdvertisedPrefixesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExamplePublicAdvertisedPrefixesClient_Patch() { diff --git a/compute/apiv1/public_delegated_prefixes_client.go b/compute/apiv1/public_delegated_prefixes_client.go index 95f13121135..e02480dad83 100644 --- a/compute/apiv1/public_delegated_prefixes_client.go +++ b/compute/apiv1/public_delegated_prefixes_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newPublicDelegatedPrefixesClientHook clientHook @@ -51,12 +55,12 @@ type internalPublicDelegatedPrefixesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListPublicDelegatedPrefixesRequest, ...gax.CallOption) (*computepb.PublicDelegatedPrefixAggregatedList, error) - Delete(context.Context, *computepb.DeletePublicDelegatedPrefixeRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListPublicDelegatedPrefixesRequest, ...gax.CallOption) *PublicDelegatedPrefixesScopedListPairIterator + Delete(context.Context, *computepb.DeletePublicDelegatedPrefixeRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetPublicDelegatedPrefixeRequest, ...gax.CallOption) (*computepb.PublicDelegatedPrefix, error) - Insert(context.Context, *computepb.InsertPublicDelegatedPrefixeRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListPublicDelegatedPrefixesRequest, ...gax.CallOption) (*computepb.PublicDelegatedPrefixList, error) - Patch(context.Context, *computepb.PatchPublicDelegatedPrefixeRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertPublicDelegatedPrefixeRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListPublicDelegatedPrefixesRequest, ...gax.CallOption) *PublicDelegatedPrefixIterator + Patch(context.Context, *computepb.PatchPublicDelegatedPrefixeRequest, ...gax.CallOption) (*Operation, error) } // PublicDelegatedPrefixesClient is a client for interacting with Google Compute Engine API. @@ -94,12 +98,12 @@ func (c *PublicDelegatedPrefixesClient) Connection() *grpc.ClientConn { } // AggregatedList lists all PublicDelegatedPrefix resources owned by the specific project across all scopes. -func (c *PublicDelegatedPrefixesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListPublicDelegatedPrefixesRequest, opts ...gax.CallOption) (*computepb.PublicDelegatedPrefixAggregatedList, error) { +func (c *PublicDelegatedPrefixesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListPublicDelegatedPrefixesRequest, opts ...gax.CallOption) *PublicDelegatedPrefixesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified PublicDelegatedPrefix in the given region. -func (c *PublicDelegatedPrefixesClient) Delete(ctx context.Context, req *computepb.DeletePublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *PublicDelegatedPrefixesClient) Delete(ctx context.Context, req *computepb.DeletePublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -109,17 +113,17 @@ func (c *PublicDelegatedPrefixesClient) Get(ctx context.Context, req *computepb. } // Insert creates a PublicDelegatedPrefix in the specified project in the given region using the parameters that are included in the request. -func (c *PublicDelegatedPrefixesClient) Insert(ctx context.Context, req *computepb.InsertPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *PublicDelegatedPrefixesClient) Insert(ctx context.Context, req *computepb.InsertPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List lists the PublicDelegatedPrefixes for a project in the given region. -func (c *PublicDelegatedPrefixesClient) List(ctx context.Context, req *computepb.ListPublicDelegatedPrefixesRequest, opts ...gax.CallOption) (*computepb.PublicDelegatedPrefixList, error) { +func (c *PublicDelegatedPrefixesClient) List(ctx context.Context, req *computepb.ListPublicDelegatedPrefixesRequest, opts ...gax.CallOption) *PublicDelegatedPrefixIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified PublicDelegatedPrefix resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *PublicDelegatedPrefixesClient) Patch(ctx context.Context, req *computepb.PatchPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *PublicDelegatedPrefixesClient) Patch(ctx context.Context, req *computepb.PatchPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -188,66 +192,101 @@ func (c *publicDelegatedPrefixesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList lists all PublicDelegatedPrefix resources owned by the specific project across all scopes. -func (c *publicDelegatedPrefixesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListPublicDelegatedPrefixesRequest, opts ...gax.CallOption) (*computepb.PublicDelegatedPrefixAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/publicDelegatedPrefixes", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *publicDelegatedPrefixesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListPublicDelegatedPrefixesRequest, opts ...gax.CallOption) *PublicDelegatedPrefixesScopedListPairIterator { + it := &PublicDelegatedPrefixesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListPublicDelegatedPrefixesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.PublicDelegatedPrefixAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]PublicDelegatedPrefixesScopedListPair, string, error) { + resp := &computepb.PublicDelegatedPrefixAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/publicDelegatedPrefixes", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]PublicDelegatedPrefixesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, PublicDelegatedPrefixesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified PublicDelegatedPrefix in the given region. -func (c *publicDelegatedPrefixesRESTClient) Delete(ctx context.Context, req *computepb.DeletePublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *publicDelegatedPrefixesRESTClient) Delete(ctx context.Context, req *computepb.DeletePublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/publicDelegatedPrefixes/%v", req.GetProject(), req.GetRegion(), req.GetPublicDelegatedPrefix()) @@ -287,7 +326,11 @@ func (c *publicDelegatedPrefixesRESTClient) Delete(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified PublicDelegatedPrefix resource in the given region. @@ -328,7 +371,7 @@ func (c *publicDelegatedPrefixesRESTClient) Get(ctx context.Context, req *comput } // Insert creates a PublicDelegatedPrefix in the specified project in the given region using the parameters that are included in the request. -func (c *publicDelegatedPrefixesRESTClient) Insert(ctx context.Context, req *computepb.InsertPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *publicDelegatedPrefixesRESTClient) Insert(ctx context.Context, req *computepb.InsertPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetPublicDelegatedPrefixResource() jsonReq, err := m.Marshal(body) @@ -375,67 +418,99 @@ func (c *publicDelegatedPrefixesRESTClient) Insert(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List lists the PublicDelegatedPrefixes for a project in the given region. -func (c *publicDelegatedPrefixesRESTClient) List(ctx context.Context, req *computepb.ListPublicDelegatedPrefixesRequest, opts ...gax.CallOption) (*computepb.PublicDelegatedPrefixList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/publicDelegatedPrefixes", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List lists the PublicDelegatedPrefixes for a project in the given region. +func (c *publicDelegatedPrefixesRESTClient) List(ctx context.Context, req *computepb.ListPublicDelegatedPrefixesRequest, opts ...gax.CallOption) *PublicDelegatedPrefixIterator { + it := &PublicDelegatedPrefixIterator{} + req = proto.Clone(req).(*computepb.ListPublicDelegatedPrefixesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.PublicDelegatedPrefixList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.PublicDelegatedPrefix, string, error) { + resp := &computepb.PublicDelegatedPrefixList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/publicDelegatedPrefixes", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified PublicDelegatedPrefix resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *publicDelegatedPrefixesRESTClient) Patch(ctx context.Context, req *computepb.PatchPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *publicDelegatedPrefixesRESTClient) Patch(ctx context.Context, req *computepb.PatchPublicDelegatedPrefixeRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetPublicDelegatedPrefixResource() jsonReq, err := m.Marshal(body) @@ -482,5 +557,62 @@ func (c *publicDelegatedPrefixesRESTClient) Patch(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// PublicDelegatedPrefixesScopedListPair is a holder type for string/*computepb.PublicDelegatedPrefixesScopedList map entries +type PublicDelegatedPrefixesScopedListPair struct { + Key string + Value *computepb.PublicDelegatedPrefixesScopedList +} + +// PublicDelegatedPrefixesScopedListPairIterator manages a stream of PublicDelegatedPrefixesScopedListPair. +type PublicDelegatedPrefixesScopedListPairIterator struct { + items []PublicDelegatedPrefixesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []PublicDelegatedPrefixesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *PublicDelegatedPrefixesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *PublicDelegatedPrefixesScopedListPairIterator) Next() (PublicDelegatedPrefixesScopedListPair, error) { + var item PublicDelegatedPrefixesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *PublicDelegatedPrefixesScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *PublicDelegatedPrefixesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/public_delegated_prefixes_client_example_test.go b/compute/apiv1/public_delegated_prefixes_client_example_test.go index c17586ce868..f5defb755c8 100644 --- a/compute/apiv1/public_delegated_prefixes_client_example_test.go +++ b/compute/apiv1/public_delegated_prefixes_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExamplePublicDelegatedPrefixesClient_AggregatedList() { req := &computepb.AggregatedListPublicDelegatedPrefixesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExamplePublicDelegatedPrefixesClient_Delete() { @@ -122,12 +129,18 @@ func ExamplePublicDelegatedPrefixesClient_List() { req := &computepb.ListPublicDelegatedPrefixesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExamplePublicDelegatedPrefixesClient_Patch() { diff --git a/compute/apiv1/region_autoscalers_client.go b/compute/apiv1/region_autoscalers_client.go index a79e0a2ece3..a6a5d57dbab 100644 --- a/compute/apiv1/region_autoscalers_client.go +++ b/compute/apiv1/region_autoscalers_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionAutoscalersClientHook clientHook @@ -51,12 +54,12 @@ type internalRegionAutoscalersClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionAutoscalerRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionAutoscalerRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionAutoscalerRequest, ...gax.CallOption) (*computepb.Autoscaler, error) - Insert(context.Context, *computepb.InsertRegionAutoscalerRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionAutoscalersRequest, ...gax.CallOption) (*computepb.RegionAutoscalerList, error) - Patch(context.Context, *computepb.PatchRegionAutoscalerRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateRegionAutoscalerRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRegionAutoscalerRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionAutoscalersRequest, ...gax.CallOption) *AutoscalerIterator + Patch(context.Context, *computepb.PatchRegionAutoscalerRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateRegionAutoscalerRequest, ...gax.CallOption) (*Operation, error) } // RegionAutoscalersClient is a client for interacting with Google Compute Engine API. @@ -94,7 +97,7 @@ func (c *RegionAutoscalersClient) Connection() *grpc.ClientConn { } // Delete deletes the specified autoscaler. -func (c *RegionAutoscalersClient) Delete(ctx context.Context, req *computepb.DeleteRegionAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionAutoscalersClient) Delete(ctx context.Context, req *computepb.DeleteRegionAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -104,22 +107,22 @@ func (c *RegionAutoscalersClient) Get(ctx context.Context, req *computepb.GetReg } // Insert creates an autoscaler in the specified project using the data included in the request. -func (c *RegionAutoscalersClient) Insert(ctx context.Context, req *computepb.InsertRegionAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionAutoscalersClient) Insert(ctx context.Context, req *computepb.InsertRegionAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of autoscalers contained within the specified region. -func (c *RegionAutoscalersClient) List(ctx context.Context, req *computepb.ListRegionAutoscalersRequest, opts ...gax.CallOption) (*computepb.RegionAutoscalerList, error) { +func (c *RegionAutoscalersClient) List(ctx context.Context, req *computepb.ListRegionAutoscalersRequest, opts ...gax.CallOption) *AutoscalerIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates an autoscaler in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *RegionAutoscalersClient) Patch(ctx context.Context, req *computepb.PatchRegionAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionAutoscalersClient) Patch(ctx context.Context, req *computepb.PatchRegionAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // Update updates an autoscaler in the specified project using the data included in the request. -func (c *RegionAutoscalersClient) Update(ctx context.Context, req *computepb.UpdateRegionAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionAutoscalersClient) Update(ctx context.Context, req *computepb.UpdateRegionAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -188,7 +191,7 @@ func (c *regionAutoscalersRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified autoscaler. -func (c *regionAutoscalersRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionAutoscalersRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/autoscalers/%v", req.GetProject(), req.GetRegion(), req.GetAutoscaler()) @@ -228,7 +231,11 @@ func (c *regionAutoscalersRESTClient) Delete(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified autoscaler. @@ -269,7 +276,7 @@ func (c *regionAutoscalersRESTClient) Get(ctx context.Context, req *computepb.Ge } // Insert creates an autoscaler in the specified project using the data included in the request. -func (c *regionAutoscalersRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionAutoscalersRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAutoscalerResource() jsonReq, err := m.Marshal(body) @@ -316,67 +323,99 @@ func (c *regionAutoscalersRESTClient) Insert(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of autoscalers contained within the specified region. -func (c *regionAutoscalersRESTClient) List(ctx context.Context, req *computepb.ListRegionAutoscalersRequest, opts ...gax.CallOption) (*computepb.RegionAutoscalerList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/autoscalers", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of autoscalers contained within the specified region. +func (c *regionAutoscalersRESTClient) List(ctx context.Context, req *computepb.ListRegionAutoscalersRequest, opts ...gax.CallOption) *AutoscalerIterator { + it := &AutoscalerIterator{} + req = proto.Clone(req).(*computepb.ListRegionAutoscalersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RegionAutoscalerList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Autoscaler, string, error) { + resp := &computepb.RegionAutoscalerList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/autoscalers", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates an autoscaler in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *regionAutoscalersRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionAutoscalersRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAutoscalerResource() jsonReq, err := m.Marshal(body) @@ -426,11 +465,15 @@ func (c *regionAutoscalersRESTClient) Patch(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates an autoscaler in the specified project using the data included in the request. -func (c *regionAutoscalersRESTClient) Update(ctx context.Context, req *computepb.UpdateRegionAutoscalerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionAutoscalersRESTClient) Update(ctx context.Context, req *computepb.UpdateRegionAutoscalerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetAutoscalerResource() jsonReq, err := m.Marshal(body) @@ -480,5 +523,9 @@ func (c *regionAutoscalersRESTClient) Update(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } diff --git a/compute/apiv1/region_autoscalers_client_example_test.go b/compute/apiv1/region_autoscalers_client_example_test.go index b3cf73327a8..4b7cd981566 100644 --- a/compute/apiv1/region_autoscalers_client_example_test.go +++ b/compute/apiv1/region_autoscalers_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleRegionAutoscalersClient_List() { req := &computepb.ListRegionAutoscalersRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionAutoscalersClient_Patch() { diff --git a/compute/apiv1/region_backend_services_client.go b/compute/apiv1/region_backend_services_client.go index adebf4252b4..5c94123ec90 100644 --- a/compute/apiv1/region_backend_services_client.go +++ b/compute/apiv1/region_backend_services_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionBackendServicesClientHook clientHook @@ -52,13 +55,13 @@ type internalRegionBackendServicesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionBackendServiceRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionBackendServiceRequest, ...gax.CallOption) (*computepb.BackendService, error) GetHealth(context.Context, *computepb.GetHealthRegionBackendServiceRequest, ...gax.CallOption) (*computepb.BackendServiceGroupHealth, error) - Insert(context.Context, *computepb.InsertRegionBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionBackendServicesRequest, ...gax.CallOption) (*computepb.BackendServiceList, error) - Patch(context.Context, *computepb.PatchRegionBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateRegionBackendServiceRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRegionBackendServiceRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionBackendServicesRequest, ...gax.CallOption) *BackendServiceIterator + Patch(context.Context, *computepb.PatchRegionBackendServiceRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateRegionBackendServiceRequest, ...gax.CallOption) (*Operation, error) } // RegionBackendServicesClient is a client for interacting with Google Compute Engine API. @@ -96,7 +99,7 @@ func (c *RegionBackendServicesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified regional BackendService resource. -func (c *RegionBackendServicesClient) Delete(ctx context.Context, req *computepb.DeleteRegionBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionBackendServicesClient) Delete(ctx context.Context, req *computepb.DeleteRegionBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -111,22 +114,22 @@ func (c *RegionBackendServicesClient) GetHealth(ctx context.Context, req *comput } // Insert creates a regional BackendService resource in the specified project using the data included in the request. For more information, see Backend services overview. -func (c *RegionBackendServicesClient) Insert(ctx context.Context, req *computepb.InsertRegionBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionBackendServicesClient) Insert(ctx context.Context, req *computepb.InsertRegionBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of regional BackendService resources available to the specified project in the given region. -func (c *RegionBackendServicesClient) List(ctx context.Context, req *computepb.ListRegionBackendServicesRequest, opts ...gax.CallOption) (*computepb.BackendServiceList, error) { +func (c *RegionBackendServicesClient) List(ctx context.Context, req *computepb.ListRegionBackendServicesRequest, opts ...gax.CallOption) *BackendServiceIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates the specified regional BackendService resource with the data included in the request. For more information, see Understanding backend services This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *RegionBackendServicesClient) Patch(ctx context.Context, req *computepb.PatchRegionBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionBackendServicesClient) Patch(ctx context.Context, req *computepb.PatchRegionBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // Update updates the specified regional BackendService resource with the data included in the request. For more information, see Backend services overview. -func (c *RegionBackendServicesClient) Update(ctx context.Context, req *computepb.UpdateRegionBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionBackendServicesClient) Update(ctx context.Context, req *computepb.UpdateRegionBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -195,7 +198,7 @@ func (c *regionBackendServicesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified regional BackendService resource. -func (c *regionBackendServicesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionBackendServicesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/backendServices/%v", req.GetProject(), req.GetRegion(), req.GetBackendService()) @@ -235,7 +238,11 @@ func (c *regionBackendServicesRESTClient) Delete(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified regional BackendService resource. @@ -320,7 +327,7 @@ func (c *regionBackendServicesRESTClient) GetHealth(ctx context.Context, req *co } // Insert creates a regional BackendService resource in the specified project using the data included in the request. For more information, see Backend services overview. -func (c *regionBackendServicesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionBackendServicesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBackendServiceResource() jsonReq, err := m.Marshal(body) @@ -367,67 +374,99 @@ func (c *regionBackendServicesRESTClient) Insert(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of regional BackendService resources available to the specified project in the given region. -func (c *regionBackendServicesRESTClient) List(ctx context.Context, req *computepb.ListRegionBackendServicesRequest, opts ...gax.CallOption) (*computepb.BackendServiceList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/backendServices", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of regional BackendService resources available to the specified project in the given region. +func (c *regionBackendServicesRESTClient) List(ctx context.Context, req *computepb.ListRegionBackendServicesRequest, opts ...gax.CallOption) *BackendServiceIterator { + it := &BackendServiceIterator{} + req = proto.Clone(req).(*computepb.ListRegionBackendServicesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.BackendServiceList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.BackendService, string, error) { + resp := &computepb.BackendServiceList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/backendServices", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates the specified regional BackendService resource with the data included in the request. For more information, see Understanding backend services This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *regionBackendServicesRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionBackendServicesRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBackendServiceResource() jsonReq, err := m.Marshal(body) @@ -474,11 +513,15 @@ func (c *regionBackendServicesRESTClient) Patch(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates the specified regional BackendService resource with the data included in the request. For more information, see Backend services overview. -func (c *regionBackendServicesRESTClient) Update(ctx context.Context, req *computepb.UpdateRegionBackendServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionBackendServicesRESTClient) Update(ctx context.Context, req *computepb.UpdateRegionBackendServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBackendServiceResource() jsonReq, err := m.Marshal(body) @@ -525,5 +568,9 @@ func (c *regionBackendServicesRESTClient) Update(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } diff --git a/compute/apiv1/region_backend_services_client_example_test.go b/compute/apiv1/region_backend_services_client_example_test.go index 389fa3210c5..304bba45fcc 100644 --- a/compute/apiv1/region_backend_services_client_example_test.go +++ b/compute/apiv1/region_backend_services_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -122,12 +123,18 @@ func ExampleRegionBackendServicesClient_List() { req := &computepb.ListRegionBackendServicesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionBackendServicesClient_Patch() { diff --git a/compute/apiv1/region_commitments_client.go b/compute/apiv1/region_commitments_client.go index 20c9a1929e8..8edbac135fd 100644 --- a/compute/apiv1/region_commitments_client.go +++ b/compute/apiv1/region_commitments_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionCommitmentsClientHook clientHook @@ -49,10 +53,10 @@ type internalRegionCommitmentsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListRegionCommitmentsRequest, ...gax.CallOption) (*computepb.CommitmentAggregatedList, error) + AggregatedList(context.Context, *computepb.AggregatedListRegionCommitmentsRequest, ...gax.CallOption) *CommitmentsScopedListPairIterator Get(context.Context, *computepb.GetRegionCommitmentRequest, ...gax.CallOption) (*computepb.Commitment, error) - Insert(context.Context, *computepb.InsertRegionCommitmentRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionCommitmentsRequest, ...gax.CallOption) (*computepb.CommitmentList, error) + Insert(context.Context, *computepb.InsertRegionCommitmentRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionCommitmentsRequest, ...gax.CallOption) *CommitmentIterator } // RegionCommitmentsClient is a client for interacting with Google Compute Engine API. @@ -90,7 +94,7 @@ func (c *RegionCommitmentsClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of commitments. -func (c *RegionCommitmentsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListRegionCommitmentsRequest, opts ...gax.CallOption) (*computepb.CommitmentAggregatedList, error) { +func (c *RegionCommitmentsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListRegionCommitmentsRequest, opts ...gax.CallOption) *CommitmentsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } @@ -100,12 +104,12 @@ func (c *RegionCommitmentsClient) Get(ctx context.Context, req *computepb.GetReg } // Insert creates a commitment in the specified project using the data included in the request. -func (c *RegionCommitmentsClient) Insert(ctx context.Context, req *computepb.InsertRegionCommitmentRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionCommitmentsClient) Insert(ctx context.Context, req *computepb.InsertRegionCommitmentRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of commitments contained within the specified region. -func (c *RegionCommitmentsClient) List(ctx context.Context, req *computepb.ListRegionCommitmentsRequest, opts ...gax.CallOption) (*computepb.CommitmentList, error) { +func (c *RegionCommitmentsClient) List(ctx context.Context, req *computepb.ListRegionCommitmentsRequest, opts ...gax.CallOption) *CommitmentIterator { return c.internalClient.List(ctx, req, opts...) } @@ -174,62 +178,97 @@ func (c *regionCommitmentsRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of commitments. -func (c *regionCommitmentsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListRegionCommitmentsRequest, opts ...gax.CallOption) (*computepb.CommitmentAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/commitments", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *regionCommitmentsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListRegionCommitmentsRequest, opts ...gax.CallOption) *CommitmentsScopedListPairIterator { + it := &CommitmentsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListRegionCommitmentsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.CommitmentAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]CommitmentsScopedListPair, string, error) { + resp := &computepb.CommitmentAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/commitments", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]CommitmentsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, CommitmentsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Get returns the specified commitment resource. Gets a list of available commitments by making a list() request. @@ -270,7 +309,7 @@ func (c *regionCommitmentsRESTClient) Get(ctx context.Context, req *computepb.Ge } // Insert creates a commitment in the specified project using the data included in the request. -func (c *regionCommitmentsRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionCommitmentRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionCommitmentsRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionCommitmentRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetCommitmentResource() jsonReq, err := m.Marshal(body) @@ -317,61 +356,193 @@ func (c *regionCommitmentsRESTClient) Insert(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List retrieves a list of commitments contained within the specified region. -func (c *regionCommitmentsRESTClient) List(ctx context.Context, req *computepb.ListRegionCommitmentsRequest, opts ...gax.CallOption) (*computepb.CommitmentList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/commitments", req.GetProject(), req.GetRegion()) +func (c *regionCommitmentsRESTClient) List(ctx context.Context, req *computepb.ListRegionCommitmentsRequest, opts ...gax.CallOption) *CommitmentIterator { + it := &CommitmentIterator{} + req = proto.Clone(req).(*computepb.ListRegionCommitmentsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Commitment, string, error) { + resp := &computepb.CommitmentList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/commitments", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it +} - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } +// CommitmentIterator manages a stream of *computepb.Commitment. +type CommitmentIterator struct { + items []*computepb.Commitment + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Commitment, nextPageToken string, err error) +} - baseUrl.RawQuery = params.Encode() +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *CommitmentIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *CommitmentIterator) Next() (*computepb.Commitment, error) { + var item *computepb.Commitment + if err := it.nextFunc(); err != nil { + return item, err } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +func (it *CommitmentIterator) bufLen() int { + return len(it.items) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +func (it *CommitmentIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// CommitmentsScopedListPair is a holder type for string/*computepb.CommitmentsScopedList map entries +type CommitmentsScopedListPair struct { + Key string + Value *computepb.CommitmentsScopedList +} + +// CommitmentsScopedListPairIterator manages a stream of CommitmentsScopedListPair. +type CommitmentsScopedListPairIterator struct { + items []CommitmentsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []CommitmentsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *CommitmentsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *CommitmentsScopedListPairIterator) Next() (CommitmentsScopedListPair, error) { + var item CommitmentsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.CommitmentList{} +func (it *CommitmentsScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *CommitmentsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/region_commitments_client_example_test.go b/compute/apiv1/region_commitments_client_example_test.go index 5cc685667d4..e568f8f4456 100644 --- a/compute/apiv1/region_commitments_client_example_test.go +++ b/compute/apiv1/region_commitments_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleRegionCommitmentsClient_AggregatedList() { req := &computepb.AggregatedListRegionCommitmentsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionCommitmentsClient_Get() { @@ -103,10 +110,16 @@ func ExampleRegionCommitmentsClient_List() { req := &computepb.ListRegionCommitmentsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/region_disk_types_client.go b/compute/apiv1/region_disk_types_client.go index 6ee47aaf1fd..3d078448742 100644 --- a/compute/apiv1/region_disk_types_client.go +++ b/compute/apiv1/region_disk_types_client.go @@ -20,10 +20,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +33,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionDiskTypesClientHook clientHook @@ -47,7 +50,7 @@ type internalRegionDiskTypesClient interface { setGoogleClientInfo(...string) Connection() *grpc.ClientConn Get(context.Context, *computepb.GetRegionDiskTypeRequest, ...gax.CallOption) (*computepb.DiskType, error) - List(context.Context, *computepb.ListRegionDiskTypesRequest, ...gax.CallOption) (*computepb.RegionDiskTypeList, error) + List(context.Context, *computepb.ListRegionDiskTypesRequest, ...gax.CallOption) *DiskTypeIterator } // RegionDiskTypesClient is a client for interacting with Google Compute Engine API. @@ -90,7 +93,7 @@ func (c *RegionDiskTypesClient) Get(ctx context.Context, req *computepb.GetRegio } // List retrieves a list of regional disk types available to the specified project. -func (c *RegionDiskTypesClient) List(ctx context.Context, req *computepb.ListRegionDiskTypesRequest, opts ...gax.CallOption) (*computepb.RegionDiskTypeList, error) { +func (c *RegionDiskTypesClient) List(ctx context.Context, req *computepb.ListRegionDiskTypesRequest, opts ...gax.CallOption) *DiskTypeIterator { return c.internalClient.List(ctx, req, opts...) } @@ -196,57 +199,85 @@ func (c *regionDiskTypesRESTClient) Get(ctx context.Context, req *computepb.GetR } // List retrieves a list of regional disk types available to the specified project. -func (c *regionDiskTypesRESTClient) List(ctx context.Context, req *computepb.ListRegionDiskTypesRequest, opts ...gax.CallOption) (*computepb.RegionDiskTypeList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/diskTypes", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +func (c *regionDiskTypesRESTClient) List(ctx context.Context, req *computepb.ListRegionDiskTypesRequest, opts ...gax.CallOption) *DiskTypeIterator { + it := &DiskTypeIterator{} + req = proto.Clone(req).(*computepb.ListRegionDiskTypesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.DiskType, string, error) { + resp := &computepb.RegionDiskTypeList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/diskTypes", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RegionDiskTypeList{} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - return rsp, unm.Unmarshal(buf, rsp) + return it } diff --git a/compute/apiv1/region_disk_types_client_example_test.go b/compute/apiv1/region_disk_types_client_example_test.go index a7d34452891..da1e34ccbbb 100644 --- a/compute/apiv1/region_disk_types_client_example_test.go +++ b/compute/apiv1/region_disk_types_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,10 +66,16 @@ func ExampleRegionDiskTypesClient_List() { req := &computepb.ListRegionDiskTypesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/region_disks_client.go b/compute/apiv1/region_disks_client.go index 2e5d6e97a0f..90138e41212 100644 --- a/compute/apiv1/region_disks_client.go +++ b/compute/apiv1/region_disks_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionDisksClientHook clientHook @@ -57,17 +60,17 @@ type internalRegionDisksClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddResourcePolicies(context.Context, *computepb.AddResourcePoliciesRegionDiskRequest, ...gax.CallOption) (*computepb.Operation, error) - CreateSnapshot(context.Context, *computepb.CreateSnapshotRegionDiskRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteRegionDiskRequest, ...gax.CallOption) (*computepb.Operation, error) + AddResourcePolicies(context.Context, *computepb.AddResourcePoliciesRegionDiskRequest, ...gax.CallOption) (*Operation, error) + CreateSnapshot(context.Context, *computepb.CreateSnapshotRegionDiskRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteRegionDiskRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionDiskRequest, ...gax.CallOption) (*computepb.Disk, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyRegionDiskRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertRegionDiskRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionDisksRequest, ...gax.CallOption) (*computepb.DiskList, error) - RemoveResourcePolicies(context.Context, *computepb.RemoveResourcePoliciesRegionDiskRequest, ...gax.CallOption) (*computepb.Operation, error) - Resize(context.Context, *computepb.ResizeRegionDiskRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRegionDiskRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionDisksRequest, ...gax.CallOption) *DiskIterator + RemoveResourcePolicies(context.Context, *computepb.RemoveResourcePoliciesRegionDiskRequest, ...gax.CallOption) (*Operation, error) + Resize(context.Context, *computepb.ResizeRegionDiskRequest, ...gax.CallOption) (*Operation, error) SetIamPolicy(context.Context, *computepb.SetIamPolicyRegionDiskRequest, ...gax.CallOption) (*computepb.Policy, error) - SetLabels(context.Context, *computepb.SetLabelsRegionDiskRequest, ...gax.CallOption) (*computepb.Operation, error) + SetLabels(context.Context, *computepb.SetLabelsRegionDiskRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsRegionDiskRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -106,17 +109,17 @@ func (c *RegionDisksClient) Connection() *grpc.ClientConn { } // AddResourcePolicies adds existing resource policies to a regional disk. You can only add one policy which will be applied to this disk for scheduling snapshot creation. -func (c *RegionDisksClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionDisksClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddResourcePolicies(ctx, req, opts...) } // CreateSnapshot creates a snapshot of this regional disk. -func (c *RegionDisksClient) CreateSnapshot(ctx context.Context, req *computepb.CreateSnapshotRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionDisksClient) CreateSnapshot(ctx context.Context, req *computepb.CreateSnapshotRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.CreateSnapshot(ctx, req, opts...) } // Delete deletes the specified regional persistent disk. Deleting a regional disk removes all the replicas of its data permanently and is irreversible. However, deleting a disk does not delete any snapshots previously made from the disk. You must separately delete snapshots. -func (c *RegionDisksClient) Delete(ctx context.Context, req *computepb.DeleteRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionDisksClient) Delete(ctx context.Context, req *computepb.DeleteRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -131,22 +134,22 @@ func (c *RegionDisksClient) GetIamPolicy(ctx context.Context, req *computepb.Get } // Insert creates a persistent regional disk in the specified project using the data included in the request. -func (c *RegionDisksClient) Insert(ctx context.Context, req *computepb.InsertRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionDisksClient) Insert(ctx context.Context, req *computepb.InsertRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of persistent disks contained within the specified region. -func (c *RegionDisksClient) List(ctx context.Context, req *computepb.ListRegionDisksRequest, opts ...gax.CallOption) (*computepb.DiskList, error) { +func (c *RegionDisksClient) List(ctx context.Context, req *computepb.ListRegionDisksRequest, opts ...gax.CallOption) *DiskIterator { return c.internalClient.List(ctx, req, opts...) } // RemoveResourcePolicies removes resource policies from a regional disk. -func (c *RegionDisksClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionDisksClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemoveResourcePolicies(ctx, req, opts...) } // Resize resizes the specified regional persistent disk. -func (c *RegionDisksClient) Resize(ctx context.Context, req *computepb.ResizeRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionDisksClient) Resize(ctx context.Context, req *computepb.ResizeRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Resize(ctx, req, opts...) } @@ -156,7 +159,7 @@ func (c *RegionDisksClient) SetIamPolicy(ctx context.Context, req *computepb.Set } // SetLabels sets the labels on the target regional disk. -func (c *RegionDisksClient) SetLabels(ctx context.Context, req *computepb.SetLabelsRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionDisksClient) SetLabels(ctx context.Context, req *computepb.SetLabelsRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetLabels(ctx, req, opts...) } @@ -230,7 +233,7 @@ func (c *regionDisksRESTClient) Connection() *grpc.ClientConn { } // AddResourcePolicies adds existing resource policies to a regional disk. You can only add one policy which will be applied to this disk for scheduling snapshot creation. -func (c *regionDisksRESTClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionDisksRESTClient) AddResourcePolicies(ctx context.Context, req *computepb.AddResourcePoliciesRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionDisksAddResourcePoliciesRequestResource() jsonReq, err := m.Marshal(body) @@ -277,11 +280,15 @@ func (c *regionDisksRESTClient) AddResourcePolicies(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // CreateSnapshot creates a snapshot of this regional disk. -func (c *regionDisksRESTClient) CreateSnapshot(ctx context.Context, req *computepb.CreateSnapshotRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionDisksRESTClient) CreateSnapshot(ctx context.Context, req *computepb.CreateSnapshotRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSnapshotResource() jsonReq, err := m.Marshal(body) @@ -328,11 +335,15 @@ func (c *regionDisksRESTClient) CreateSnapshot(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified regional persistent disk. Deleting a regional disk removes all the replicas of its data permanently and is irreversible. However, deleting a disk does not delete any snapshots previously made from the disk. You must separately delete snapshots. -func (c *regionDisksRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionDisksRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/disks/%v", req.GetProject(), req.GetRegion(), req.GetDisk()) @@ -372,7 +383,11 @@ func (c *regionDisksRESTClient) Delete(ctx context.Context, req *computepb.Delet unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns a specified regional persistent disk. @@ -457,7 +472,7 @@ func (c *regionDisksRESTClient) GetIamPolicy(ctx context.Context, req *computepb } // Insert creates a persistent regional disk in the specified project using the data included in the request. -func (c *regionDisksRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionDisksRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetDiskResource() jsonReq, err := m.Marshal(body) @@ -507,67 +522,99 @@ func (c *regionDisksRESTClient) Insert(ctx context.Context, req *computepb.Inser unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of persistent disks contained within the specified region. -func (c *regionDisksRESTClient) List(ctx context.Context, req *computepb.ListRegionDisksRequest, opts ...gax.CallOption) (*computepb.DiskList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/disks", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of persistent disks contained within the specified region. +func (c *regionDisksRESTClient) List(ctx context.Context, req *computepb.ListRegionDisksRequest, opts ...gax.CallOption) *DiskIterator { + it := &DiskIterator{} + req = proto.Clone(req).(*computepb.ListRegionDisksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.DiskList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Disk, string, error) { + resp := &computepb.DiskList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/disks", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // RemoveResourcePolicies removes resource policies from a regional disk. -func (c *regionDisksRESTClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionDisksRESTClient) RemoveResourcePolicies(ctx context.Context, req *computepb.RemoveResourcePoliciesRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionDisksRemoveResourcePoliciesRequestResource() jsonReq, err := m.Marshal(body) @@ -614,11 +661,15 @@ func (c *regionDisksRESTClient) RemoveResourcePolicies(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Resize resizes the specified regional persistent disk. -func (c *regionDisksRESTClient) Resize(ctx context.Context, req *computepb.ResizeRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionDisksRESTClient) Resize(ctx context.Context, req *computepb.ResizeRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionDisksResizeRequestResource() jsonReq, err := m.Marshal(body) @@ -665,7 +716,11 @@ func (c *regionDisksRESTClient) Resize(ctx context.Context, req *computepb.Resiz unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -713,7 +768,7 @@ func (c *regionDisksRESTClient) SetIamPolicy(ctx context.Context, req *computepb } // SetLabels sets the labels on the target regional disk. -func (c *regionDisksRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsRegionDiskRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionDisksRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsRegionDiskRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionSetLabelsRequestResource() jsonReq, err := m.Marshal(body) @@ -760,7 +815,11 @@ func (c *regionDisksRESTClient) SetLabels(ctx context.Context, req *computepb.Se unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. diff --git a/compute/apiv1/region_disks_client_example_test.go b/compute/apiv1/region_disks_client_example_test.go index fbef3946358..36d621414e9 100644 --- a/compute/apiv1/region_disks_client_example_test.go +++ b/compute/apiv1/region_disks_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -160,12 +161,18 @@ func ExampleRegionDisksClient_List() { req := &computepb.ListRegionDisksRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionDisksClient_RemoveResourcePolicies() { diff --git a/compute/apiv1/region_health_check_services_client.go b/compute/apiv1/region_health_check_services_client.go index bc2deda8d5f..97ae6a11c88 100644 --- a/compute/apiv1/region_health_check_services_client.go +++ b/compute/apiv1/region_health_check_services_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionHealthCheckServicesClientHook clientHook @@ -50,11 +53,11 @@ type internalRegionHealthCheckServicesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionHealthCheckServiceRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionHealthCheckServiceRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionHealthCheckServiceRequest, ...gax.CallOption) (*computepb.HealthCheckService, error) - Insert(context.Context, *computepb.InsertRegionHealthCheckServiceRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionHealthCheckServicesRequest, ...gax.CallOption) (*computepb.HealthCheckServicesList, error) - Patch(context.Context, *computepb.PatchRegionHealthCheckServiceRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRegionHealthCheckServiceRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionHealthCheckServicesRequest, ...gax.CallOption) *HealthCheckServiceIterator + Patch(context.Context, *computepb.PatchRegionHealthCheckServiceRequest, ...gax.CallOption) (*Operation, error) } // RegionHealthCheckServicesClient is a client for interacting with Google Compute Engine API. @@ -92,7 +95,7 @@ func (c *RegionHealthCheckServicesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified regional HealthCheckService. -func (c *RegionHealthCheckServicesClient) Delete(ctx context.Context, req *computepb.DeleteRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionHealthCheckServicesClient) Delete(ctx context.Context, req *computepb.DeleteRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -102,17 +105,17 @@ func (c *RegionHealthCheckServicesClient) Get(ctx context.Context, req *computep } // Insert creates a regional HealthCheckService resource in the specified project and region using the data included in the request. -func (c *RegionHealthCheckServicesClient) Insert(ctx context.Context, req *computepb.InsertRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionHealthCheckServicesClient) Insert(ctx context.Context, req *computepb.InsertRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List lists all the HealthCheckService resources that have been configured for the specified project in the given region. -func (c *RegionHealthCheckServicesClient) List(ctx context.Context, req *computepb.ListRegionHealthCheckServicesRequest, opts ...gax.CallOption) (*computepb.HealthCheckServicesList, error) { +func (c *RegionHealthCheckServicesClient) List(ctx context.Context, req *computepb.ListRegionHealthCheckServicesRequest, opts ...gax.CallOption) *HealthCheckServiceIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates the specified regional HealthCheckService resource with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *RegionHealthCheckServicesClient) Patch(ctx context.Context, req *computepb.PatchRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionHealthCheckServicesClient) Patch(ctx context.Context, req *computepb.PatchRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -181,7 +184,7 @@ func (c *regionHealthCheckServicesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified regional HealthCheckService. -func (c *regionHealthCheckServicesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionHealthCheckServicesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/healthCheckServices/%v", req.GetProject(), req.GetRegion(), req.GetHealthCheckService()) @@ -221,7 +224,11 @@ func (c *regionHealthCheckServicesRESTClient) Delete(ctx context.Context, req *c unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified regional HealthCheckService resource. @@ -262,7 +269,7 @@ func (c *regionHealthCheckServicesRESTClient) Get(ctx context.Context, req *comp } // Insert creates a regional HealthCheckService resource in the specified project and region using the data included in the request. -func (c *regionHealthCheckServicesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionHealthCheckServicesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetHealthCheckServiceResource() jsonReq, err := m.Marshal(body) @@ -309,67 +316,99 @@ func (c *regionHealthCheckServicesRESTClient) Insert(ctx context.Context, req *c unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List lists all the HealthCheckService resources that have been configured for the specified project in the given region. -func (c *regionHealthCheckServicesRESTClient) List(ctx context.Context, req *computepb.ListRegionHealthCheckServicesRequest, opts ...gax.CallOption) (*computepb.HealthCheckServicesList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/healthCheckServices", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List lists all the HealthCheckService resources that have been configured for the specified project in the given region. +func (c *regionHealthCheckServicesRESTClient) List(ctx context.Context, req *computepb.ListRegionHealthCheckServicesRequest, opts ...gax.CallOption) *HealthCheckServiceIterator { + it := &HealthCheckServiceIterator{} + req = proto.Clone(req).(*computepb.ListRegionHealthCheckServicesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.HealthCheckServicesList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.HealthCheckService, string, error) { + resp := &computepb.HealthCheckServicesList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/healthCheckServices", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates the specified regional HealthCheckService resource with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *regionHealthCheckServicesRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionHealthCheckServicesRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionHealthCheckServiceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetHealthCheckServiceResource() jsonReq, err := m.Marshal(body) @@ -416,5 +455,56 @@ func (c *regionHealthCheckServicesRESTClient) Patch(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// HealthCheckServiceIterator manages a stream of *computepb.HealthCheckService. +type HealthCheckServiceIterator struct { + items []*computepb.HealthCheckService + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.HealthCheckService, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *HealthCheckServiceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *HealthCheckServiceIterator) Next() (*computepb.HealthCheckService, error) { + var item *computepb.HealthCheckService + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *HealthCheckServiceIterator) bufLen() int { + return len(it.items) +} + +func (it *HealthCheckServiceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/region_health_check_services_client_example_test.go b/compute/apiv1/region_health_check_services_client_example_test.go index bbaf17d8152..121e76a1455 100644 --- a/compute/apiv1/region_health_check_services_client_example_test.go +++ b/compute/apiv1/region_health_check_services_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleRegionHealthCheckServicesClient_List() { req := &computepb.ListRegionHealthCheckServicesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionHealthCheckServicesClient_Patch() { diff --git a/compute/apiv1/region_health_checks_client.go b/compute/apiv1/region_health_checks_client.go index ca66eb0a050..4ea7bc29e67 100644 --- a/compute/apiv1/region_health_checks_client.go +++ b/compute/apiv1/region_health_checks_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionHealthChecksClientHook clientHook @@ -51,12 +54,12 @@ type internalRegionHealthChecksClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionHealthCheckRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionHealthCheckRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionHealthCheckRequest, ...gax.CallOption) (*computepb.HealthCheck, error) - Insert(context.Context, *computepb.InsertRegionHealthCheckRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionHealthChecksRequest, ...gax.CallOption) (*computepb.HealthCheckList, error) - Patch(context.Context, *computepb.PatchRegionHealthCheckRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateRegionHealthCheckRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRegionHealthCheckRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionHealthChecksRequest, ...gax.CallOption) *HealthCheckIterator + Patch(context.Context, *computepb.PatchRegionHealthCheckRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateRegionHealthCheckRequest, ...gax.CallOption) (*Operation, error) } // RegionHealthChecksClient is a client for interacting with Google Compute Engine API. @@ -94,7 +97,7 @@ func (c *RegionHealthChecksClient) Connection() *grpc.ClientConn { } // Delete deletes the specified HealthCheck resource. -func (c *RegionHealthChecksClient) Delete(ctx context.Context, req *computepb.DeleteRegionHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionHealthChecksClient) Delete(ctx context.Context, req *computepb.DeleteRegionHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -104,22 +107,22 @@ func (c *RegionHealthChecksClient) Get(ctx context.Context, req *computepb.GetRe } // Insert creates a HealthCheck resource in the specified project using the data included in the request. -func (c *RegionHealthChecksClient) Insert(ctx context.Context, req *computepb.InsertRegionHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionHealthChecksClient) Insert(ctx context.Context, req *computepb.InsertRegionHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of HealthCheck resources available to the specified project. -func (c *RegionHealthChecksClient) List(ctx context.Context, req *computepb.ListRegionHealthChecksRequest, opts ...gax.CallOption) (*computepb.HealthCheckList, error) { +func (c *RegionHealthChecksClient) List(ctx context.Context, req *computepb.ListRegionHealthChecksRequest, opts ...gax.CallOption) *HealthCheckIterator { return c.internalClient.List(ctx, req, opts...) } // Patch updates a HealthCheck resource in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *RegionHealthChecksClient) Patch(ctx context.Context, req *computepb.PatchRegionHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionHealthChecksClient) Patch(ctx context.Context, req *computepb.PatchRegionHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // Update updates a HealthCheck resource in the specified project using the data included in the request. -func (c *RegionHealthChecksClient) Update(ctx context.Context, req *computepb.UpdateRegionHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionHealthChecksClient) Update(ctx context.Context, req *computepb.UpdateRegionHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -188,7 +191,7 @@ func (c *regionHealthChecksRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified HealthCheck resource. -func (c *regionHealthChecksRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionHealthChecksRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/healthChecks/%v", req.GetProject(), req.GetRegion(), req.GetHealthCheck()) @@ -228,7 +231,11 @@ func (c *regionHealthChecksRESTClient) Delete(ctx context.Context, req *computep unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified HealthCheck resource. Gets a list of available health checks by making a list() request. @@ -269,7 +276,7 @@ func (c *regionHealthChecksRESTClient) Get(ctx context.Context, req *computepb.G } // Insert creates a HealthCheck resource in the specified project using the data included in the request. -func (c *regionHealthChecksRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionHealthChecksRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetHealthCheckResource() jsonReq, err := m.Marshal(body) @@ -316,67 +323,99 @@ func (c *regionHealthChecksRESTClient) Insert(ctx context.Context, req *computep unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of HealthCheck resources available to the specified project. -func (c *regionHealthChecksRESTClient) List(ctx context.Context, req *computepb.ListRegionHealthChecksRequest, opts ...gax.CallOption) (*computepb.HealthCheckList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/healthChecks", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of HealthCheck resources available to the specified project. +func (c *regionHealthChecksRESTClient) List(ctx context.Context, req *computepb.ListRegionHealthChecksRequest, opts ...gax.CallOption) *HealthCheckIterator { + it := &HealthCheckIterator{} + req = proto.Clone(req).(*computepb.ListRegionHealthChecksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.HealthCheckList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.HealthCheck, string, error) { + resp := &computepb.HealthCheckList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/healthChecks", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates a HealthCheck resource in the specified project using the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *regionHealthChecksRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionHealthChecksRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetHealthCheckResource() jsonReq, err := m.Marshal(body) @@ -423,11 +462,15 @@ func (c *regionHealthChecksRESTClient) Patch(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates a HealthCheck resource in the specified project using the data included in the request. -func (c *regionHealthChecksRESTClient) Update(ctx context.Context, req *computepb.UpdateRegionHealthCheckRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionHealthChecksRESTClient) Update(ctx context.Context, req *computepb.UpdateRegionHealthCheckRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetHealthCheckResource() jsonReq, err := m.Marshal(body) @@ -474,5 +517,9 @@ func (c *regionHealthChecksRESTClient) Update(ctx context.Context, req *computep unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } diff --git a/compute/apiv1/region_health_checks_client_example_test.go b/compute/apiv1/region_health_checks_client_example_test.go index 2264ab8e671..7420c3eabce 100644 --- a/compute/apiv1/region_health_checks_client_example_test.go +++ b/compute/apiv1/region_health_checks_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleRegionHealthChecksClient_List() { req := &computepb.ListRegionHealthChecksRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionHealthChecksClient_Patch() { diff --git a/compute/apiv1/region_instance_group_managers_client.go b/compute/apiv1/region_instance_group_managers_client.go index 6d8c9153399..d8d1cd719b2 100644 --- a/compute/apiv1/region_instance_group_managers_client.go +++ b/compute/apiv1/region_instance_group_managers_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionInstanceGroupManagersClientHook clientHook @@ -64,25 +67,25 @@ type internalRegionInstanceGroupManagersClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AbandonInstances(context.Context, *computepb.AbandonInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - ApplyUpdatesToInstances(context.Context, *computepb.ApplyUpdatesToInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - CreateInstances(context.Context, *computepb.CreateInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - DeleteInstances(context.Context, *computepb.DeleteInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - DeletePerInstanceConfigs(context.Context, *computepb.DeletePerInstanceConfigsRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) + AbandonInstances(context.Context, *computepb.AbandonInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + ApplyUpdatesToInstances(context.Context, *computepb.ApplyUpdatesToInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + CreateInstances(context.Context, *computepb.CreateInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + DeleteInstances(context.Context, *computepb.DeleteInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + DeletePerInstanceConfigs(context.Context, *computepb.DeletePerInstanceConfigsRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.InstanceGroupManager, error) - Insert(context.Context, *computepb.InsertRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionInstanceGroupManagersRequest, ...gax.CallOption) (*computepb.RegionInstanceGroupManagerList, error) - ListErrors(context.Context, *computepb.ListErrorsRegionInstanceGroupManagersRequest, ...gax.CallOption) (*computepb.RegionInstanceGroupManagersListErrorsResponse, error) - ListManagedInstances(context.Context, *computepb.ListManagedInstancesRegionInstanceGroupManagersRequest, ...gax.CallOption) (*computepb.RegionInstanceGroupManagersListInstancesResponse, error) - ListPerInstanceConfigs(context.Context, *computepb.ListPerInstanceConfigsRegionInstanceGroupManagersRequest, ...gax.CallOption) (*computepb.RegionInstanceGroupManagersListInstanceConfigsResp, error) - Patch(context.Context, *computepb.PatchRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - PatchPerInstanceConfigs(context.Context, *computepb.PatchPerInstanceConfigsRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - RecreateInstances(context.Context, *computepb.RecreateInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - Resize(context.Context, *computepb.ResizeRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - SetInstanceTemplate(context.Context, *computepb.SetInstanceTemplateRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - SetTargetPools(context.Context, *computepb.SetTargetPoolsRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) - UpdatePerInstanceConfigs(context.Context, *computepb.UpdatePerInstanceConfigsRegionInstanceGroupManagerRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionInstanceGroupManagersRequest, ...gax.CallOption) *InstanceGroupManagerIterator + ListErrors(context.Context, *computepb.ListErrorsRegionInstanceGroupManagersRequest, ...gax.CallOption) *InstanceManagedByIgmErrorIterator + ListManagedInstances(context.Context, *computepb.ListManagedInstancesRegionInstanceGroupManagersRequest, ...gax.CallOption) *ManagedInstanceIterator + ListPerInstanceConfigs(context.Context, *computepb.ListPerInstanceConfigsRegionInstanceGroupManagersRequest, ...gax.CallOption) *PerInstanceConfigIterator + Patch(context.Context, *computepb.PatchRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + PatchPerInstanceConfigs(context.Context, *computepb.PatchPerInstanceConfigsRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + RecreateInstances(context.Context, *computepb.RecreateInstancesRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + Resize(context.Context, *computepb.ResizeRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + SetInstanceTemplate(context.Context, *computepb.SetInstanceTemplateRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + SetTargetPools(context.Context, *computepb.SetTargetPoolsRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) + UpdatePerInstanceConfigs(context.Context, *computepb.UpdatePerInstanceConfigsRegionInstanceGroupManagerRequest, ...gax.CallOption) (*Operation, error) } // RegionInstanceGroupManagersClient is a client for interacting with Google Compute Engine API. @@ -124,22 +127,22 @@ func (c *RegionInstanceGroupManagersClient) Connection() *grpc.ClientConn { // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *RegionInstanceGroupManagersClient) AbandonInstances(ctx context.Context, req *computepb.AbandonInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) AbandonInstances(ctx context.Context, req *computepb.AbandonInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AbandonInstances(ctx, req, opts...) } // ApplyUpdatesToInstances apply updates to selected instances the managed instance group. -func (c *RegionInstanceGroupManagersClient) ApplyUpdatesToInstances(ctx context.Context, req *computepb.ApplyUpdatesToInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) ApplyUpdatesToInstances(ctx context.Context, req *computepb.ApplyUpdatesToInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.ApplyUpdatesToInstances(ctx, req, opts...) } // CreateInstances creates instances with per-instance configs in this regional managed instance group. Instances are created using the current instance template. The create instances operation is marked DONE if the createInstances request is successful. The underlying actions take additional time. You must separately verify the status of the creating or actions with the listmanagedinstances method. -func (c *RegionInstanceGroupManagersClient) CreateInstances(ctx context.Context, req *computepb.CreateInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) CreateInstances(ctx context.Context, req *computepb.CreateInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.CreateInstances(ctx, req, opts...) } // Delete deletes the specified managed instance group and all of the instances in that group. -func (c *RegionInstanceGroupManagersClient) Delete(ctx context.Context, req *computepb.DeleteRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) Delete(ctx context.Context, req *computepb.DeleteRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -148,12 +151,12 @@ func (c *RegionInstanceGroupManagersClient) Delete(ctx context.Context, req *com // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *RegionInstanceGroupManagersClient) DeleteInstances(ctx context.Context, req *computepb.DeleteInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) DeleteInstances(ctx context.Context, req *computepb.DeleteInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DeleteInstances(ctx, req, opts...) } // DeletePerInstanceConfigs deletes selected per-instance configs for the managed instance group. -func (c *RegionInstanceGroupManagersClient) DeletePerInstanceConfigs(ctx context.Context, req *computepb.DeletePerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) DeletePerInstanceConfigs(ctx context.Context, req *computepb.DeletePerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.DeletePerInstanceConfigs(ctx, req, opts...) } @@ -165,37 +168,37 @@ func (c *RegionInstanceGroupManagersClient) Get(ctx context.Context, req *comput // Insert creates a managed instance group using the information that you specify in the request. After the group is created, instances in the group are created using the specified instance template. This operation is marked as DONE when the group is created even if the instances in the group have not yet been created. You must separately verify the status of the individual instances with the listmanagedinstances method. // // A regional managed instance group can contain up to 2000 instances. -func (c *RegionInstanceGroupManagersClient) Insert(ctx context.Context, req *computepb.InsertRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) Insert(ctx context.Context, req *computepb.InsertRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of managed instance groups that are contained within the specified region. -func (c *RegionInstanceGroupManagersClient) List(ctx context.Context, req *computepb.ListRegionInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupManagerList, error) { +func (c *RegionInstanceGroupManagersClient) List(ctx context.Context, req *computepb.ListRegionInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceGroupManagerIterator { return c.internalClient.List(ctx, req, opts...) } // ListErrors lists all errors thrown by actions on instances for a given regional managed instance group. The filter and orderBy query parameters are not supported. -func (c *RegionInstanceGroupManagersClient) ListErrors(ctx context.Context, req *computepb.ListErrorsRegionInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupManagersListErrorsResponse, error) { +func (c *RegionInstanceGroupManagersClient) ListErrors(ctx context.Context, req *computepb.ListErrorsRegionInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceManagedByIgmErrorIterator { return c.internalClient.ListErrors(ctx, req, opts...) } // ListManagedInstances lists the instances in the managed instance group and instances that are scheduled to be created. The list includes any current actions that the group has scheduled for its instances. The orderBy query parameter is not supported. -func (c *RegionInstanceGroupManagersClient) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesRegionInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupManagersListInstancesResponse, error) { +func (c *RegionInstanceGroupManagersClient) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesRegionInstanceGroupManagersRequest, opts ...gax.CallOption) *ManagedInstanceIterator { return c.internalClient.ListManagedInstances(ctx, req, opts...) } // ListPerInstanceConfigs lists all of the per-instance configs defined for the managed instance group. The orderBy query parameter is not supported. -func (c *RegionInstanceGroupManagersClient) ListPerInstanceConfigs(ctx context.Context, req *computepb.ListPerInstanceConfigsRegionInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupManagersListInstanceConfigsResp, error) { +func (c *RegionInstanceGroupManagersClient) ListPerInstanceConfigs(ctx context.Context, req *computepb.ListPerInstanceConfigsRegionInstanceGroupManagersRequest, opts ...gax.CallOption) *PerInstanceConfigIterator { return c.internalClient.ListPerInstanceConfigs(ctx, req, opts...) } // Patch updates a managed instance group using the information that you specify in the request. This operation is marked as DONE when the group is patched even if the instances in the group are still in the process of being patched. You must separately verify the status of the individual instances with the listmanagedinstances method. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *RegionInstanceGroupManagersClient) Patch(ctx context.Context, req *computepb.PatchRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) Patch(ctx context.Context, req *computepb.PatchRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // PatchPerInstanceConfigs inserts or patches per-instance configs for the managed instance group. perInstanceConfig.name (at http://perInstanceConfig.name) serves as a key used to distinguish whether to perform insert or patch. -func (c *RegionInstanceGroupManagersClient) PatchPerInstanceConfigs(ctx context.Context, req *computepb.PatchPerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) PatchPerInstanceConfigs(ctx context.Context, req *computepb.PatchPerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.PatchPerInstanceConfigs(ctx, req, opts...) } @@ -204,7 +207,7 @@ func (c *RegionInstanceGroupManagersClient) PatchPerInstanceConfigs(ctx context. // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *RegionInstanceGroupManagersClient) RecreateInstances(ctx context.Context, req *computepb.RecreateInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) RecreateInstances(ctx context.Context, req *computepb.RecreateInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RecreateInstances(ctx, req, opts...) } @@ -213,22 +216,22 @@ func (c *RegionInstanceGroupManagersClient) RecreateInstances(ctx context.Contex // The resize operation is marked DONE if the resize request is successful. The underlying actions take additional time. You must separately verify the status of the creating or deleting actions with the listmanagedinstances method. // // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. -func (c *RegionInstanceGroupManagersClient) Resize(ctx context.Context, req *computepb.ResizeRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) Resize(ctx context.Context, req *computepb.ResizeRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Resize(ctx, req, opts...) } // SetInstanceTemplate sets the instance template to use when creating new instances or recreating instances in this group. Existing instances are not affected. -func (c *RegionInstanceGroupManagersClient) SetInstanceTemplate(ctx context.Context, req *computepb.SetInstanceTemplateRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) SetInstanceTemplate(ctx context.Context, req *computepb.SetInstanceTemplateRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetInstanceTemplate(ctx, req, opts...) } // SetTargetPools modifies the target pools to which all new instances in this group are assigned. Existing instances in the group are not affected. -func (c *RegionInstanceGroupManagersClient) SetTargetPools(ctx context.Context, req *computepb.SetTargetPoolsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) SetTargetPools(ctx context.Context, req *computepb.SetTargetPoolsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetTargetPools(ctx, req, opts...) } // UpdatePerInstanceConfigs inserts or updates per-instance configs for the managed instance group. perInstanceConfig.name (at http://perInstanceConfig.name) serves as a key used to distinguish whether to perform insert or patch. -func (c *RegionInstanceGroupManagersClient) UpdatePerInstanceConfigs(ctx context.Context, req *computepb.UpdatePerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupManagersClient) UpdatePerInstanceConfigs(ctx context.Context, req *computepb.UpdatePerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.UpdatePerInstanceConfigs(ctx, req, opts...) } @@ -301,7 +304,7 @@ func (c *regionInstanceGroupManagersRESTClient) Connection() *grpc.ClientConn { // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *regionInstanceGroupManagersRESTClient) AbandonInstances(ctx context.Context, req *computepb.AbandonInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) AbandonInstances(ctx context.Context, req *computepb.AbandonInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagersAbandonInstancesRequestResource() jsonReq, err := m.Marshal(body) @@ -348,11 +351,15 @@ func (c *regionInstanceGroupManagersRESTClient) AbandonInstances(ctx context.Con unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // ApplyUpdatesToInstances apply updates to selected instances the managed instance group. -func (c *regionInstanceGroupManagersRESTClient) ApplyUpdatesToInstances(ctx context.Context, req *computepb.ApplyUpdatesToInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) ApplyUpdatesToInstances(ctx context.Context, req *computepb.ApplyUpdatesToInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagersApplyUpdatesRequestResource() jsonReq, err := m.Marshal(body) @@ -392,11 +399,15 @@ func (c *regionInstanceGroupManagersRESTClient) ApplyUpdatesToInstances(ctx cont unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // CreateInstances creates instances with per-instance configs in this regional managed instance group. Instances are created using the current instance template. The create instances operation is marked DONE if the createInstances request is successful. The underlying actions take additional time. You must separately verify the status of the creating or actions with the listmanagedinstances method. -func (c *regionInstanceGroupManagersRESTClient) CreateInstances(ctx context.Context, req *computepb.CreateInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) CreateInstances(ctx context.Context, req *computepb.CreateInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagersCreateInstancesRequestResource() jsonReq, err := m.Marshal(body) @@ -443,11 +454,15 @@ func (c *regionInstanceGroupManagersRESTClient) CreateInstances(ctx context.Cont unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified managed instance group and all of the instances in that group. -func (c *regionInstanceGroupManagersRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers/%v", req.GetProject(), req.GetRegion(), req.GetInstanceGroupManager()) @@ -487,7 +502,11 @@ func (c *regionInstanceGroupManagersRESTClient) Delete(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DeleteInstances flags the specified instances in the managed instance group to be immediately deleted. The instances are also removed from any target pools of which they were a member. This method reduces the targetSize of the managed instance group by the number of instances that you delete. The deleteInstances operation is marked DONE if the deleteInstances request is successful. The underlying actions take additional time. You must separately verify the status of the deleting action with the listmanagedinstances method. @@ -495,7 +514,7 @@ func (c *regionInstanceGroupManagersRESTClient) Delete(ctx context.Context, req // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *regionInstanceGroupManagersRESTClient) DeleteInstances(ctx context.Context, req *computepb.DeleteInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) DeleteInstances(ctx context.Context, req *computepb.DeleteInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagersDeleteInstancesRequestResource() jsonReq, err := m.Marshal(body) @@ -542,11 +561,15 @@ func (c *regionInstanceGroupManagersRESTClient) DeleteInstances(ctx context.Cont unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // DeletePerInstanceConfigs deletes selected per-instance configs for the managed instance group. -func (c *regionInstanceGroupManagersRESTClient) DeletePerInstanceConfigs(ctx context.Context, req *computepb.DeletePerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) DeletePerInstanceConfigs(ctx context.Context, req *computepb.DeletePerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagerDeleteInstanceConfigReqResource() jsonReq, err := m.Marshal(body) @@ -586,7 +609,11 @@ func (c *regionInstanceGroupManagersRESTClient) DeletePerInstanceConfigs(ctx con unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns all of the details about the specified managed instance group. @@ -629,7 +656,7 @@ func (c *regionInstanceGroupManagersRESTClient) Get(ctx context.Context, req *co // Insert creates a managed instance group using the information that you specify in the request. After the group is created, instances in the group are created using the specified instance template. This operation is marked as DONE when the group is created even if the instances in the group have not yet been created. You must separately verify the status of the individual instances with the listmanagedinstances method. // // A regional managed instance group can contain up to 2000 instances. -func (c *regionInstanceGroupManagersRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagerResource() jsonReq, err := m.Marshal(body) @@ -676,235 +703,351 @@ func (c *regionInstanceGroupManagersRESTClient) Insert(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of managed instance groups that are contained within the specified region. -func (c *regionInstanceGroupManagersRESTClient) List(ctx context.Context, req *computepb.ListRegionInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupManagerList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of managed instance groups that are contained within the specified region. +func (c *regionInstanceGroupManagersRESTClient) List(ctx context.Context, req *computepb.ListRegionInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceGroupManagerIterator { + it := &InstanceGroupManagerIterator{} + req = proto.Clone(req).(*computepb.ListRegionInstanceGroupManagersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RegionInstanceGroupManagerList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InstanceGroupManager, string, error) { + resp := &computepb.RegionInstanceGroupManagerList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListErrors lists all errors thrown by actions on instances for a given regional managed instance group. The filter and orderBy query parameters are not supported. -func (c *regionInstanceGroupManagersRESTClient) ListErrors(ctx context.Context, req *computepb.ListErrorsRegionInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupManagersListErrorsResponse, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers/%v/listErrors", req.GetProject(), req.GetRegion(), req.GetInstanceGroupManager()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *regionInstanceGroupManagersRESTClient) ListErrors(ctx context.Context, req *computepb.ListErrorsRegionInstanceGroupManagersRequest, opts ...gax.CallOption) *InstanceManagedByIgmErrorIterator { + it := &InstanceManagedByIgmErrorIterator{} + req = proto.Clone(req).(*computepb.ListErrorsRegionInstanceGroupManagersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RegionInstanceGroupManagersListErrorsResponse{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InstanceManagedByIgmError, string, error) { + resp := &computepb.RegionInstanceGroupManagersListErrorsResponse{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers/%v/listErrors", req.GetProject(), req.GetRegion(), req.GetInstanceGroupManager()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListManagedInstances lists the instances in the managed instance group and instances that are scheduled to be created. The list includes any current actions that the group has scheduled for its instances. The orderBy query parameter is not supported. -func (c *regionInstanceGroupManagersRESTClient) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesRegionInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupManagersListInstancesResponse, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers/%v/listManagedInstances", req.GetProject(), req.GetRegion(), req.GetInstanceGroupManager()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *regionInstanceGroupManagersRESTClient) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesRegionInstanceGroupManagersRequest, opts ...gax.CallOption) *ManagedInstanceIterator { + it := &ManagedInstanceIterator{} + req = proto.Clone(req).(*computepb.ListManagedInstancesRegionInstanceGroupManagersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RegionInstanceGroupManagersListInstancesResponse{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.ManagedInstance, string, error) { + resp := &computepb.RegionInstanceGroupManagersListInstancesResponse{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers/%v/listManagedInstances", req.GetProject(), req.GetRegion(), req.GetInstanceGroupManager()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetManagedInstances(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListPerInstanceConfigs lists all of the per-instance configs defined for the managed instance group. The orderBy query parameter is not supported. -func (c *regionInstanceGroupManagersRESTClient) ListPerInstanceConfigs(ctx context.Context, req *computepb.ListPerInstanceConfigsRegionInstanceGroupManagersRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupManagersListInstanceConfigsResp, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers/%v/listPerInstanceConfigs", req.GetProject(), req.GetRegion(), req.GetInstanceGroupManager()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *regionInstanceGroupManagersRESTClient) ListPerInstanceConfigs(ctx context.Context, req *computepb.ListPerInstanceConfigsRegionInstanceGroupManagersRequest, opts ...gax.CallOption) *PerInstanceConfigIterator { + it := &PerInstanceConfigIterator{} + req = proto.Clone(req).(*computepb.ListPerInstanceConfigsRegionInstanceGroupManagersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RegionInstanceGroupManagersListInstanceConfigsResp{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.PerInstanceConfig, string, error) { + resp := &computepb.RegionInstanceGroupManagersListInstanceConfigsResp{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers/%v/listPerInstanceConfigs", req.GetProject(), req.GetRegion(), req.GetInstanceGroupManager()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch updates a managed instance group using the information that you specify in the request. This operation is marked as DONE when the group is patched even if the instances in the group are still in the process of being patched. You must separately verify the status of the individual instances with the listmanagedinstances method. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *regionInstanceGroupManagersRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetInstanceGroupManagerResource() jsonReq, err := m.Marshal(body) @@ -951,11 +1094,15 @@ func (c *regionInstanceGroupManagersRESTClient) Patch(ctx context.Context, req * unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // PatchPerInstanceConfigs inserts or patches per-instance configs for the managed instance group. perInstanceConfig.name (at http://perInstanceConfig.name) serves as a key used to distinguish whether to perform insert or patch. -func (c *regionInstanceGroupManagersRESTClient) PatchPerInstanceConfigs(ctx context.Context, req *computepb.PatchPerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) PatchPerInstanceConfigs(ctx context.Context, req *computepb.PatchPerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagerPatchInstanceConfigReqResource() jsonReq, err := m.Marshal(body) @@ -1002,7 +1149,11 @@ func (c *regionInstanceGroupManagersRESTClient) PatchPerInstanceConfigs(ctx cont unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // RecreateInstances flags the specified VM instances in the managed instance group to be immediately recreated. Each instance is recreated using the group’s current configuration. This operation is marked as DONE when the flag is set even if the instances have not yet been recreated. You must separately verify the status of each instance by checking its currentAction field; for more information, see Checking the status of managed instances. @@ -1010,7 +1161,7 @@ func (c *regionInstanceGroupManagersRESTClient) PatchPerInstanceConfigs(ctx cont // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. // // You can specify a maximum of 1000 instances with this method per request. -func (c *regionInstanceGroupManagersRESTClient) RecreateInstances(ctx context.Context, req *computepb.RecreateInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) RecreateInstances(ctx context.Context, req *computepb.RecreateInstancesRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagersRecreateRequestResource() jsonReq, err := m.Marshal(body) @@ -1057,7 +1208,11 @@ func (c *regionInstanceGroupManagersRESTClient) RecreateInstances(ctx context.Co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Resize changes the intended size of the managed instance group. If you increase the size, the group creates new instances using the current instance template. If you decrease the size, the group deletes one or more instances. @@ -1065,7 +1220,7 @@ func (c *regionInstanceGroupManagersRESTClient) RecreateInstances(ctx context.Co // The resize operation is marked DONE if the resize request is successful. The underlying actions take additional time. You must separately verify the status of the creating or deleting actions with the listmanagedinstances method. // // If the group is part of a backend service that has enabled connection draining, it can take up to 60 seconds after the connection draining duration has elapsed before the VM instance is removed or deleted. -func (c *regionInstanceGroupManagersRESTClient) Resize(ctx context.Context, req *computepb.ResizeRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) Resize(ctx context.Context, req *computepb.ResizeRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroupManagers/%v/resize", req.GetProject(), req.GetRegion(), req.GetInstanceGroupManager()) @@ -1108,11 +1263,15 @@ func (c *regionInstanceGroupManagersRESTClient) Resize(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetInstanceTemplate sets the instance template to use when creating new instances or recreating instances in this group. Existing instances are not affected. -func (c *regionInstanceGroupManagersRESTClient) SetInstanceTemplate(ctx context.Context, req *computepb.SetInstanceTemplateRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) SetInstanceTemplate(ctx context.Context, req *computepb.SetInstanceTemplateRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagersSetTemplateRequestResource() jsonReq, err := m.Marshal(body) @@ -1159,11 +1318,15 @@ func (c *regionInstanceGroupManagersRESTClient) SetInstanceTemplate(ctx context. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetTargetPools modifies the target pools to which all new instances in this group are assigned. Existing instances in the group are not affected. -func (c *regionInstanceGroupManagersRESTClient) SetTargetPools(ctx context.Context, req *computepb.SetTargetPoolsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) SetTargetPools(ctx context.Context, req *computepb.SetTargetPoolsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagersSetTargetPoolsRequestResource() jsonReq, err := m.Marshal(body) @@ -1210,11 +1373,15 @@ func (c *regionInstanceGroupManagersRESTClient) SetTargetPools(ctx context.Conte unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // UpdatePerInstanceConfigs inserts or updates per-instance configs for the managed instance group. perInstanceConfig.name (at http://perInstanceConfig.name) serves as a key used to distinguish whether to perform insert or patch. -func (c *regionInstanceGroupManagersRESTClient) UpdatePerInstanceConfigs(ctx context.Context, req *computepb.UpdatePerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupManagersRESTClient) UpdatePerInstanceConfigs(ctx context.Context, req *computepb.UpdatePerInstanceConfigsRegionInstanceGroupManagerRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupManagerUpdateInstanceConfigReqResource() jsonReq, err := m.Marshal(body) @@ -1261,5 +1428,9 @@ func (c *regionInstanceGroupManagersRESTClient) UpdatePerInstanceConfigs(ctx con unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } diff --git a/compute/apiv1/region_instance_group_managers_client_example_test.go b/compute/apiv1/region_instance_group_managers_client_example_test.go index cf0c18b6003..43c71420304 100644 --- a/compute/apiv1/region_instance_group_managers_client_example_test.go +++ b/compute/apiv1/region_instance_group_managers_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -198,12 +199,18 @@ func ExampleRegionInstanceGroupManagersClient_List() { req := &computepb.ListRegionInstanceGroupManagersRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionInstanceGroupManagersClient_ListErrors() { @@ -217,12 +224,18 @@ func ExampleRegionInstanceGroupManagersClient_ListErrors() { req := &computepb.ListErrorsRegionInstanceGroupManagersRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListErrors(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListErrors(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionInstanceGroupManagersClient_ListManagedInstances() { @@ -236,12 +249,18 @@ func ExampleRegionInstanceGroupManagersClient_ListManagedInstances() { req := &computepb.ListManagedInstancesRegionInstanceGroupManagersRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListManagedInstances(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListManagedInstances(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionInstanceGroupManagersClient_ListPerInstanceConfigs() { @@ -255,12 +274,18 @@ func ExampleRegionInstanceGroupManagersClient_ListPerInstanceConfigs() { req := &computepb.ListPerInstanceConfigsRegionInstanceGroupManagersRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListPerInstanceConfigs(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListPerInstanceConfigs(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionInstanceGroupManagersClient_Patch() { diff --git a/compute/apiv1/region_instance_groups_client.go b/compute/apiv1/region_instance_groups_client.go index 3468e7f2da9..a452ac8ac69 100644 --- a/compute/apiv1/region_instance_groups_client.go +++ b/compute/apiv1/region_instance_groups_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionInstanceGroupsClientHook clientHook @@ -50,9 +53,9 @@ type internalRegionInstanceGroupsClient interface { setGoogleClientInfo(...string) Connection() *grpc.ClientConn Get(context.Context, *computepb.GetRegionInstanceGroupRequest, ...gax.CallOption) (*computepb.InstanceGroup, error) - List(context.Context, *computepb.ListRegionInstanceGroupsRequest, ...gax.CallOption) (*computepb.RegionInstanceGroupList, error) - ListInstances(context.Context, *computepb.ListInstancesRegionInstanceGroupsRequest, ...gax.CallOption) (*computepb.RegionInstanceGroupsListInstances, error) - SetNamedPorts(context.Context, *computepb.SetNamedPortsRegionInstanceGroupRequest, ...gax.CallOption) (*computepb.Operation, error) + List(context.Context, *computepb.ListRegionInstanceGroupsRequest, ...gax.CallOption) *InstanceGroupIterator + ListInstances(context.Context, *computepb.ListInstancesRegionInstanceGroupsRequest, ...gax.CallOption) *InstanceWithNamedPortsIterator + SetNamedPorts(context.Context, *computepb.SetNamedPortsRegionInstanceGroupRequest, ...gax.CallOption) (*Operation, error) } // RegionInstanceGroupsClient is a client for interacting with Google Compute Engine API. @@ -95,17 +98,17 @@ func (c *RegionInstanceGroupsClient) Get(ctx context.Context, req *computepb.Get } // List retrieves the list of instance group resources contained within the specified region. -func (c *RegionInstanceGroupsClient) List(ctx context.Context, req *computepb.ListRegionInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupList, error) { +func (c *RegionInstanceGroupsClient) List(ctx context.Context, req *computepb.ListRegionInstanceGroupsRequest, opts ...gax.CallOption) *InstanceGroupIterator { return c.internalClient.List(ctx, req, opts...) } // ListInstances lists the instances in the specified instance group and displays information about the named ports. Depending on the specified options, this method can list all instances or only the instances that are running. The orderBy query parameter is not supported. -func (c *RegionInstanceGroupsClient) ListInstances(ctx context.Context, req *computepb.ListInstancesRegionInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupsListInstances, error) { +func (c *RegionInstanceGroupsClient) ListInstances(ctx context.Context, req *computepb.ListInstancesRegionInstanceGroupsRequest, opts ...gax.CallOption) *InstanceWithNamedPortsIterator { return c.internalClient.ListInstances(ctx, req, opts...) } // SetNamedPorts sets the named ports for the specified regional instance group. -func (c *RegionInstanceGroupsClient) SetNamedPorts(ctx context.Context, req *computepb.SetNamedPortsRegionInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstanceGroupsClient) SetNamedPorts(ctx context.Context, req *computepb.SetNamedPortsRegionInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetNamedPorts(ctx, req, opts...) } @@ -211,126 +214,181 @@ func (c *regionInstanceGroupsRESTClient) Get(ctx context.Context, req *computepb } // List retrieves the list of instance group resources contained within the specified region. -func (c *regionInstanceGroupsRESTClient) List(ctx context.Context, req *computepb.ListRegionInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroups", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *regionInstanceGroupsRESTClient) List(ctx context.Context, req *computepb.ListRegionInstanceGroupsRequest, opts ...gax.CallOption) *InstanceGroupIterator { + it := &InstanceGroupIterator{} + req = proto.Clone(req).(*computepb.ListRegionInstanceGroupsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RegionInstanceGroupList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InstanceGroup, string, error) { + resp := &computepb.RegionInstanceGroupList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroups", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListInstances lists the instances in the specified instance group and displays information about the named ports. Depending on the specified options, this method can list all instances or only the instances that are running. The orderBy query parameter is not supported. -func (c *regionInstanceGroupsRESTClient) ListInstances(ctx context.Context, req *computepb.ListInstancesRegionInstanceGroupsRequest, opts ...gax.CallOption) (*computepb.RegionInstanceGroupsListInstances, error) { - m := protojson.MarshalOptions{AllowPartial: true} - body := req.GetRegionInstanceGroupsListInstancesRequestResource() - jsonReq, err := m.Marshal(body) - if err != nil { - return nil, err - } - - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroups/%v/listInstances", req.GetProject(), req.GetRegion(), req.GetInstanceGroup()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *regionInstanceGroupsRESTClient) ListInstances(ctx context.Context, req *computepb.ListInstancesRegionInstanceGroupsRequest, opts ...gax.CallOption) *InstanceWithNamedPortsIterator { + it := &InstanceWithNamedPortsIterator{} + req = proto.Clone(req).(*computepb.ListInstancesRegionInstanceGroupsRequest) + m := protojson.MarshalOptions{AllowPartial: true, UseProtoNames: false} unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RegionInstanceGroupsListInstances{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.InstanceWithNamedPorts, string, error) { + resp := &computepb.RegionInstanceGroupsListInstances{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + jsonReq, err := m.Marshal(req) + if err != nil { + return nil, "", err + } + + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/instanceGroups/%v/listInstances", req.GetProject(), req.GetRegion(), req.GetInstanceGroup()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("POST", baseUrl.String(), bytes.NewReader(jsonReq)) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetNamedPorts sets the named ports for the specified regional instance group. -func (c *regionInstanceGroupsRESTClient) SetNamedPorts(ctx context.Context, req *computepb.SetNamedPortsRegionInstanceGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstanceGroupsRESTClient) SetNamedPorts(ctx context.Context, req *computepb.SetNamedPortsRegionInstanceGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionInstanceGroupsSetNamedPortsRequestResource() jsonReq, err := m.Marshal(body) @@ -377,5 +435,9 @@ func (c *regionInstanceGroupsRESTClient) SetNamedPorts(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } diff --git a/compute/apiv1/region_instance_groups_client_example_test.go b/compute/apiv1/region_instance_groups_client_example_test.go index 646c6f1843d..bc308d08e41 100644 --- a/compute/apiv1/region_instance_groups_client_example_test.go +++ b/compute/apiv1/region_instance_groups_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,12 +66,18 @@ func ExampleRegionInstanceGroupsClient_List() { req := &computepb.ListRegionInstanceGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionInstanceGroupsClient_ListInstances() { @@ -84,12 +91,18 @@ func ExampleRegionInstanceGroupsClient_ListInstances() { req := &computepb.ListInstancesRegionInstanceGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListInstances(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListInstances(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionInstanceGroupsClient_SetNamedPorts() { diff --git a/compute/apiv1/region_instances_client.go b/compute/apiv1/region_instances_client.go index 6083abb8a1a..21ec17f3f2d 100644 --- a/compute/apiv1/region_instances_client.go +++ b/compute/apiv1/region_instances_client.go @@ -46,7 +46,7 @@ type internalRegionInstancesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - BulkInsert(context.Context, *computepb.BulkInsertRegionInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) + BulkInsert(context.Context, *computepb.BulkInsertRegionInstanceRequest, ...gax.CallOption) (*Operation, error) } // RegionInstancesClient is a client for interacting with Google Compute Engine API. @@ -84,7 +84,7 @@ func (c *RegionInstancesClient) Connection() *grpc.ClientConn { } // BulkInsert creates multiple instances in a given region. Count specifies the number of instances to create. -func (c *RegionInstancesClient) BulkInsert(ctx context.Context, req *computepb.BulkInsertRegionInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionInstancesClient) BulkInsert(ctx context.Context, req *computepb.BulkInsertRegionInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.BulkInsert(ctx, req, opts...) } @@ -153,7 +153,7 @@ func (c *regionInstancesRESTClient) Connection() *grpc.ClientConn { } // BulkInsert creates multiple instances in a given region. Count specifies the number of instances to create. -func (c *regionInstancesRESTClient) BulkInsert(ctx context.Context, req *computepb.BulkInsertRegionInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionInstancesRESTClient) BulkInsert(ctx context.Context, req *computepb.BulkInsertRegionInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetBulkInsertInstanceResourceResource() jsonReq, err := m.Marshal(body) @@ -200,5 +200,9 @@ func (c *regionInstancesRESTClient) BulkInsert(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } diff --git a/compute/apiv1/region_network_endpoint_groups_client.go b/compute/apiv1/region_network_endpoint_groups_client.go index 3e34f364630..ef6bdf7b558 100644 --- a/compute/apiv1/region_network_endpoint_groups_client.go +++ b/compute/apiv1/region_network_endpoint_groups_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionNetworkEndpointGroupsClientHook clientHook @@ -49,10 +52,10 @@ type internalRegionNetworkEndpointGroupsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.NetworkEndpointGroup, error) - Insert(context.Context, *computepb.InsertRegionNetworkEndpointGroupRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionNetworkEndpointGroupsRequest, ...gax.CallOption) (*computepb.NetworkEndpointGroupList, error) + Insert(context.Context, *computepb.InsertRegionNetworkEndpointGroupRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionNetworkEndpointGroupsRequest, ...gax.CallOption) *NetworkEndpointGroupIterator } // RegionNetworkEndpointGroupsClient is a client for interacting with Google Compute Engine API. @@ -90,7 +93,7 @@ func (c *RegionNetworkEndpointGroupsClient) Connection() *grpc.ClientConn { } // Delete deletes the specified network endpoint group. Note that the NEG cannot be deleted if it is configured as a backend of a backend service. -func (c *RegionNetworkEndpointGroupsClient) Delete(ctx context.Context, req *computepb.DeleteRegionNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionNetworkEndpointGroupsClient) Delete(ctx context.Context, req *computepb.DeleteRegionNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -100,12 +103,12 @@ func (c *RegionNetworkEndpointGroupsClient) Get(ctx context.Context, req *comput } // Insert creates a network endpoint group in the specified project using the parameters that are included in the request. -func (c *RegionNetworkEndpointGroupsClient) Insert(ctx context.Context, req *computepb.InsertRegionNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionNetworkEndpointGroupsClient) Insert(ctx context.Context, req *computepb.InsertRegionNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of regional network endpoint groups available to the specified project in the given region. -func (c *RegionNetworkEndpointGroupsClient) List(ctx context.Context, req *computepb.ListRegionNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupList, error) { +func (c *RegionNetworkEndpointGroupsClient) List(ctx context.Context, req *computepb.ListRegionNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointGroupIterator { return c.internalClient.List(ctx, req, opts...) } @@ -174,7 +177,7 @@ func (c *regionNetworkEndpointGroupsRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified network endpoint group. Note that the NEG cannot be deleted if it is configured as a backend of a backend service. -func (c *regionNetworkEndpointGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionNetworkEndpointGroupsRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/networkEndpointGroups/%v", req.GetProject(), req.GetRegion(), req.GetNetworkEndpointGroup()) @@ -214,7 +217,11 @@ func (c *regionNetworkEndpointGroupsRESTClient) Delete(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified network endpoint group. Gets a list of available network endpoint groups by making a list() request. @@ -255,7 +262,7 @@ func (c *regionNetworkEndpointGroupsRESTClient) Get(ctx context.Context, req *co } // Insert creates a network endpoint group in the specified project using the parameters that are included in the request. -func (c *regionNetworkEndpointGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionNetworkEndpointGroupRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionNetworkEndpointGroupsRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionNetworkEndpointGroupRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNetworkEndpointGroupResource() jsonReq, err := m.Marshal(body) @@ -302,61 +309,93 @@ func (c *regionNetworkEndpointGroupsRESTClient) Insert(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of regional network endpoint groups available to the specified project in the given region. -func (c *regionNetworkEndpointGroupsRESTClient) List(ctx context.Context, req *computepb.ListRegionNetworkEndpointGroupsRequest, opts ...gax.CallOption) (*computepb.NetworkEndpointGroupList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/networkEndpointGroups", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() + op := &Operation{proto: rsp} + return op, err +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +// List retrieves the list of regional network endpoint groups available to the specified project in the given region. +func (c *regionNetworkEndpointGroupsRESTClient) List(ctx context.Context, req *computepb.ListRegionNetworkEndpointGroupsRequest, opts ...gax.CallOption) *NetworkEndpointGroupIterator { + it := &NetworkEndpointGroupIterator{} + req = proto.Clone(req).(*computepb.ListRegionNetworkEndpointGroupsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NetworkEndpointGroup, string, error) { + resp := &computepb.NetworkEndpointGroupList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/networkEndpointGroups", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NetworkEndpointGroupList{} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - return rsp, unm.Unmarshal(buf, rsp) + return it } diff --git a/compute/apiv1/region_network_endpoint_groups_client_example_test.go b/compute/apiv1/region_network_endpoint_groups_client_example_test.go index 507dceea933..1c289ecec61 100644 --- a/compute/apiv1/region_network_endpoint_groups_client_example_test.go +++ b/compute/apiv1/region_network_endpoint_groups_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,10 +104,16 @@ func ExampleRegionNetworkEndpointGroupsClient_List() { req := &computepb.ListRegionNetworkEndpointGroupsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/region_notification_endpoints_client.go b/compute/apiv1/region_notification_endpoints_client.go index 774403808d9..74fc26a35e7 100644 --- a/compute/apiv1/region_notification_endpoints_client.go +++ b/compute/apiv1/region_notification_endpoints_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionNotificationEndpointsClientHook clientHook @@ -49,10 +52,10 @@ type internalRegionNotificationEndpointsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionNotificationEndpointRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionNotificationEndpointRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionNotificationEndpointRequest, ...gax.CallOption) (*computepb.NotificationEndpoint, error) - Insert(context.Context, *computepb.InsertRegionNotificationEndpointRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionNotificationEndpointsRequest, ...gax.CallOption) (*computepb.NotificationEndpointList, error) + Insert(context.Context, *computepb.InsertRegionNotificationEndpointRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionNotificationEndpointsRequest, ...gax.CallOption) *NotificationEndpointIterator } // RegionNotificationEndpointsClient is a client for interacting with Google Compute Engine API. @@ -90,7 +93,7 @@ func (c *RegionNotificationEndpointsClient) Connection() *grpc.ClientConn { } // Delete deletes the specified NotificationEndpoint in the given region -func (c *RegionNotificationEndpointsClient) Delete(ctx context.Context, req *computepb.DeleteRegionNotificationEndpointRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionNotificationEndpointsClient) Delete(ctx context.Context, req *computepb.DeleteRegionNotificationEndpointRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -100,12 +103,12 @@ func (c *RegionNotificationEndpointsClient) Get(ctx context.Context, req *comput } // Insert create a NotificationEndpoint in the specified project in the given region using the parameters that are included in the request. -func (c *RegionNotificationEndpointsClient) Insert(ctx context.Context, req *computepb.InsertRegionNotificationEndpointRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionNotificationEndpointsClient) Insert(ctx context.Context, req *computepb.InsertRegionNotificationEndpointRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List lists the NotificationEndpoints for a project in the given region. -func (c *RegionNotificationEndpointsClient) List(ctx context.Context, req *computepb.ListRegionNotificationEndpointsRequest, opts ...gax.CallOption) (*computepb.NotificationEndpointList, error) { +func (c *RegionNotificationEndpointsClient) List(ctx context.Context, req *computepb.ListRegionNotificationEndpointsRequest, opts ...gax.CallOption) *NotificationEndpointIterator { return c.internalClient.List(ctx, req, opts...) } @@ -174,7 +177,7 @@ func (c *regionNotificationEndpointsRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified NotificationEndpoint in the given region -func (c *regionNotificationEndpointsRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionNotificationEndpointRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionNotificationEndpointsRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionNotificationEndpointRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/notificationEndpoints/%v", req.GetProject(), req.GetRegion(), req.GetNotificationEndpoint()) @@ -214,7 +217,11 @@ func (c *regionNotificationEndpointsRESTClient) Delete(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified NotificationEndpoint resource in the given region. @@ -255,7 +262,7 @@ func (c *regionNotificationEndpointsRESTClient) Get(ctx context.Context, req *co } // Insert create a NotificationEndpoint in the specified project in the given region using the parameters that are included in the request. -func (c *regionNotificationEndpointsRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionNotificationEndpointRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionNotificationEndpointsRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionNotificationEndpointRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetNotificationEndpointResource() jsonReq, err := m.Marshal(body) @@ -302,61 +309,140 @@ func (c *regionNotificationEndpointsRESTClient) Insert(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List lists the NotificationEndpoints for a project in the given region. -func (c *regionNotificationEndpointsRESTClient) List(ctx context.Context, req *computepb.ListRegionNotificationEndpointsRequest, opts ...gax.CallOption) (*computepb.NotificationEndpointList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/notificationEndpoints", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *regionNotificationEndpointsRESTClient) List(ctx context.Context, req *computepb.ListRegionNotificationEndpointsRequest, opts ...gax.CallOption) *NotificationEndpointIterator { + it := &NotificationEndpointIterator{} + req = proto.Clone(req).(*computepb.ListRegionNotificationEndpointsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.NotificationEndpoint, string, error) { + resp := &computepb.NotificationEndpointList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/notificationEndpoints", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// NotificationEndpointIterator manages a stream of *computepb.NotificationEndpoint. +type NotificationEndpointIterator struct { + items []*computepb.NotificationEndpoint + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.NotificationEndpoint, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *NotificationEndpointIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *NotificationEndpointIterator) Next() (*computepb.NotificationEndpoint, error) { + var item *computepb.NotificationEndpoint + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.NotificationEndpointList{} +func (it *NotificationEndpointIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *NotificationEndpointIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/region_notification_endpoints_client_example_test.go b/compute/apiv1/region_notification_endpoints_client_example_test.go index 708851924c5..b8b3486e12c 100644 --- a/compute/apiv1/region_notification_endpoints_client_example_test.go +++ b/compute/apiv1/region_notification_endpoints_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,10 +104,16 @@ func ExampleRegionNotificationEndpointsClient_List() { req := &computepb.ListRegionNotificationEndpointsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/region_operations_client.go b/compute/apiv1/region_operations_client.go index f24dca1df36..cc2dee0abcb 100644 --- a/compute/apiv1/region_operations_client.go +++ b/compute/apiv1/region_operations_client.go @@ -20,10 +20,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +33,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionOperationsClientHook clientHook @@ -49,9 +52,9 @@ type internalRegionOperationsClient interface { setGoogleClientInfo(...string) Connection() *grpc.ClientConn Delete(context.Context, *computepb.DeleteRegionOperationRequest, ...gax.CallOption) (*computepb.DeleteRegionOperationResponse, error) - Get(context.Context, *computepb.GetRegionOperationRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionOperationsRequest, ...gax.CallOption) (*computepb.OperationList, error) - Wait(context.Context, *computepb.WaitRegionOperationRequest, ...gax.CallOption) (*computepb.Operation, error) + Get(context.Context, *computepb.GetRegionOperationRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionOperationsRequest, ...gax.CallOption) *OperationIterator + Wait(context.Context, *computepb.WaitRegionOperationRequest, ...gax.CallOption) (*Operation, error) } // RegionOperationsClient is a client for interacting with Google Compute Engine API. @@ -94,12 +97,12 @@ func (c *RegionOperationsClient) Delete(ctx context.Context, req *computepb.Dele } // Get retrieves the specified region-specific Operations resource. -func (c *RegionOperationsClient) Get(ctx context.Context, req *computepb.GetRegionOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionOperationsClient) Get(ctx context.Context, req *computepb.GetRegionOperationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Get(ctx, req, opts...) } // List retrieves a list of Operation resources contained within the specified region. -func (c *RegionOperationsClient) List(ctx context.Context, req *computepb.ListRegionOperationsRequest, opts ...gax.CallOption) (*computepb.OperationList, error) { +func (c *RegionOperationsClient) List(ctx context.Context, req *computepb.ListRegionOperationsRequest, opts ...gax.CallOption) *OperationIterator { return c.internalClient.List(ctx, req, opts...) } @@ -110,7 +113,7 @@ func (c *RegionOperationsClient) List(ctx context.Context, req *computepb.ListRe // In uncommon cases, when the server is overloaded, the request might return before the default deadline is reached, or might return after zero seconds. // // If the default deadline is reached, there is no guarantee that the operation is actually done when the method returns. Be prepared to retry if the operation is not DONE. -func (c *RegionOperationsClient) Wait(ctx context.Context, req *computepb.WaitRegionOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionOperationsClient) Wait(ctx context.Context, req *computepb.WaitRegionOperationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Wait(ctx, req, opts...) } @@ -216,7 +219,7 @@ func (c *regionOperationsRESTClient) Delete(ctx context.Context, req *computepb. } // Get retrieves the specified region-specific Operations resource. -func (c *regionOperationsRESTClient) Get(ctx context.Context, req *computepb.GetRegionOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionOperationsRESTClient) Get(ctx context.Context, req *computepb.GetRegionOperationRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/operations/%v", req.GetProject(), req.GetRegion(), req.GetOperation()) @@ -249,63 +252,95 @@ func (c *regionOperationsRESTClient) Get(ctx context.Context, req *computepb.Get unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of Operation resources contained within the specified region. -func (c *regionOperationsRESTClient) List(ctx context.Context, req *computepb.ListRegionOperationsRequest, opts ...gax.CallOption) (*computepb.OperationList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/operations", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } - defer httpRsp.Body.Close() + op := &Operation{proto: rsp} + return op, err +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +// List retrieves a list of Operation resources contained within the specified region. +func (c *regionOperationsRESTClient) List(ctx context.Context, req *computepb.ListRegionOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*computepb.ListRegionOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Operation, string, error) { + resp := &computepb.OperationList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/operations", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.OperationList{} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - return rsp, unm.Unmarshal(buf, rsp) + return it } // Wait waits for the specified Operation resource to return as DONE or for the request to approach the 2 minute deadline, and retrieves the specified Operation resource. This method differs from the GET method in that it waits for no more than the default deadline (2 minutes) and then returns the current state of the operation, which might be DONE or still in progress. @@ -315,7 +350,7 @@ func (c *regionOperationsRESTClient) List(ctx context.Context, req *computepb.Li // In uncommon cases, when the server is overloaded, the request might return before the default deadline is reached, or might return after zero seconds. // // If the default deadline is reached, there is no guarantee that the operation is actually done when the method returns. Be prepared to retry if the operation is not DONE. -func (c *regionOperationsRESTClient) Wait(ctx context.Context, req *computepb.WaitRegionOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionOperationsRESTClient) Wait(ctx context.Context, req *computepb.WaitRegionOperationRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/operations/%v/wait", req.GetProject(), req.GetRegion(), req.GetOperation()) @@ -348,5 +383,9 @@ func (c *regionOperationsRESTClient) Wait(ctx context.Context, req *computepb.Wa unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } diff --git a/compute/apiv1/region_operations_client_example_test.go b/compute/apiv1/region_operations_client_example_test.go index 75736e6becc..d8a62257750 100644 --- a/compute/apiv1/region_operations_client_example_test.go +++ b/compute/apiv1/region_operations_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -84,12 +85,18 @@ func ExampleRegionOperationsClient_List() { req := &computepb.ListRegionOperationsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionOperationsClient_Wait() { diff --git a/compute/apiv1/region_ssl_certificates_client.go b/compute/apiv1/region_ssl_certificates_client.go index 6ffb0a3e6b0..e8359951258 100644 --- a/compute/apiv1/region_ssl_certificates_client.go +++ b/compute/apiv1/region_ssl_certificates_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionSslCertificatesClientHook clientHook @@ -49,10 +52,10 @@ type internalRegionSslCertificatesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionSslCertificateRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionSslCertificateRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionSslCertificateRequest, ...gax.CallOption) (*computepb.SslCertificate, error) - Insert(context.Context, *computepb.InsertRegionSslCertificateRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionSslCertificatesRequest, ...gax.CallOption) (*computepb.SslCertificateList, error) + Insert(context.Context, *computepb.InsertRegionSslCertificateRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionSslCertificatesRequest, ...gax.CallOption) *SslCertificateIterator } // RegionSslCertificatesClient is a client for interacting with Google Compute Engine API. @@ -90,7 +93,7 @@ func (c *RegionSslCertificatesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified SslCertificate resource in the region. -func (c *RegionSslCertificatesClient) Delete(ctx context.Context, req *computepb.DeleteRegionSslCertificateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionSslCertificatesClient) Delete(ctx context.Context, req *computepb.DeleteRegionSslCertificateRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -100,12 +103,12 @@ func (c *RegionSslCertificatesClient) Get(ctx context.Context, req *computepb.Ge } // Insert creates a SslCertificate resource in the specified project and region using the data included in the request -func (c *RegionSslCertificatesClient) Insert(ctx context.Context, req *computepb.InsertRegionSslCertificateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionSslCertificatesClient) Insert(ctx context.Context, req *computepb.InsertRegionSslCertificateRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of SslCertificate resources available to the specified project in the specified region. -func (c *RegionSslCertificatesClient) List(ctx context.Context, req *computepb.ListRegionSslCertificatesRequest, opts ...gax.CallOption) (*computepb.SslCertificateList, error) { +func (c *RegionSslCertificatesClient) List(ctx context.Context, req *computepb.ListRegionSslCertificatesRequest, opts ...gax.CallOption) *SslCertificateIterator { return c.internalClient.List(ctx, req, opts...) } @@ -174,7 +177,7 @@ func (c *regionSslCertificatesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified SslCertificate resource in the region. -func (c *regionSslCertificatesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionSslCertificateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionSslCertificatesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionSslCertificateRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/sslCertificates/%v", req.GetProject(), req.GetRegion(), req.GetSslCertificate()) @@ -214,7 +217,11 @@ func (c *regionSslCertificatesRESTClient) Delete(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified SslCertificate resource in the specified region. Get a list of available SSL certificates by making a list() request. @@ -255,7 +262,7 @@ func (c *regionSslCertificatesRESTClient) Get(ctx context.Context, req *computep } // Insert creates a SslCertificate resource in the specified project and region using the data included in the request -func (c *regionSslCertificatesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionSslCertificateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionSslCertificatesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionSslCertificateRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSslCertificateResource() jsonReq, err := m.Marshal(body) @@ -302,61 +309,140 @@ func (c *regionSslCertificatesRESTClient) Insert(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List retrieves the list of SslCertificate resources available to the specified project in the specified region. -func (c *regionSslCertificatesRESTClient) List(ctx context.Context, req *computepb.ListRegionSslCertificatesRequest, opts ...gax.CallOption) (*computepb.SslCertificateList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/sslCertificates", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *regionSslCertificatesRESTClient) List(ctx context.Context, req *computepb.ListRegionSslCertificatesRequest, opts ...gax.CallOption) *SslCertificateIterator { + it := &SslCertificateIterator{} + req = proto.Clone(req).(*computepb.ListRegionSslCertificatesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.SslCertificate, string, error) { + resp := &computepb.SslCertificateList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/sslCertificates", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// SslCertificateIterator manages a stream of *computepb.SslCertificate. +type SslCertificateIterator struct { + items []*computepb.SslCertificate + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.SslCertificate, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SslCertificateIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SslCertificateIterator) Next() (*computepb.SslCertificate, error) { + var item *computepb.SslCertificate + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.SslCertificateList{} +func (it *SslCertificateIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *SslCertificateIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/region_ssl_certificates_client_example_test.go b/compute/apiv1/region_ssl_certificates_client_example_test.go index 016dcb96a14..a2b919fefa1 100644 --- a/compute/apiv1/region_ssl_certificates_client_example_test.go +++ b/compute/apiv1/region_ssl_certificates_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,10 +104,16 @@ func ExampleRegionSslCertificatesClient_List() { req := &computepb.ListRegionSslCertificatesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/region_target_http_proxies_client.go b/compute/apiv1/region_target_http_proxies_client.go index 74d3cbc9f31..df0fa1e87d6 100644 --- a/compute/apiv1/region_target_http_proxies_client.go +++ b/compute/apiv1/region_target_http_proxies_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionTargetHttpProxiesClientHook clientHook @@ -50,11 +53,11 @@ type internalRegionTargetHttpProxiesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionTargetHttpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionTargetHttpProxyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionTargetHttpProxyRequest, ...gax.CallOption) (*computepb.TargetHttpProxy, error) - Insert(context.Context, *computepb.InsertRegionTargetHttpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionTargetHttpProxiesRequest, ...gax.CallOption) (*computepb.TargetHttpProxyList, error) - SetUrlMap(context.Context, *computepb.SetUrlMapRegionTargetHttpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRegionTargetHttpProxyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionTargetHttpProxiesRequest, ...gax.CallOption) *TargetHttpProxyIterator + SetUrlMap(context.Context, *computepb.SetUrlMapRegionTargetHttpProxyRequest, ...gax.CallOption) (*Operation, error) } // RegionTargetHttpProxiesClient is a client for interacting with Google Compute Engine API. @@ -92,7 +95,7 @@ func (c *RegionTargetHttpProxiesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetHttpProxy resource. -func (c *RegionTargetHttpProxiesClient) Delete(ctx context.Context, req *computepb.DeleteRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionTargetHttpProxiesClient) Delete(ctx context.Context, req *computepb.DeleteRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -102,17 +105,17 @@ func (c *RegionTargetHttpProxiesClient) Get(ctx context.Context, req *computepb. } // Insert creates a TargetHttpProxy resource in the specified project and region using the data included in the request. -func (c *RegionTargetHttpProxiesClient) Insert(ctx context.Context, req *computepb.InsertRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionTargetHttpProxiesClient) Insert(ctx context.Context, req *computepb.InsertRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of TargetHttpProxy resources available to the specified project in the specified region. -func (c *RegionTargetHttpProxiesClient) List(ctx context.Context, req *computepb.ListRegionTargetHttpProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpProxyList, error) { +func (c *RegionTargetHttpProxiesClient) List(ctx context.Context, req *computepb.ListRegionTargetHttpProxiesRequest, opts ...gax.CallOption) *TargetHttpProxyIterator { return c.internalClient.List(ctx, req, opts...) } // SetUrlMap changes the URL map for TargetHttpProxy. -func (c *RegionTargetHttpProxiesClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionTargetHttpProxiesClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetUrlMap(ctx, req, opts...) } @@ -181,7 +184,7 @@ func (c *regionTargetHttpProxiesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetHttpProxy resource. -func (c *regionTargetHttpProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionTargetHttpProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetHttpProxies/%v", req.GetProject(), req.GetRegion(), req.GetTargetHttpProxy()) @@ -221,7 +224,11 @@ func (c *regionTargetHttpProxiesRESTClient) Delete(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified TargetHttpProxy resource in the specified region. Gets a list of available target HTTP proxies by making a list() request. @@ -262,7 +269,7 @@ func (c *regionTargetHttpProxiesRESTClient) Get(ctx context.Context, req *comput } // Insert creates a TargetHttpProxy resource in the specified project and region using the data included in the request. -func (c *regionTargetHttpProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionTargetHttpProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetHttpProxyResource() jsonReq, err := m.Marshal(body) @@ -309,67 +316,99 @@ func (c *regionTargetHttpProxiesRESTClient) Insert(ctx context.Context, req *com unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of TargetHttpProxy resources available to the specified project in the specified region. -func (c *regionTargetHttpProxiesRESTClient) List(ctx context.Context, req *computepb.ListRegionTargetHttpProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpProxyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetHttpProxies", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of TargetHttpProxy resources available to the specified project in the specified region. +func (c *regionTargetHttpProxiesRESTClient) List(ctx context.Context, req *computepb.ListRegionTargetHttpProxiesRequest, opts ...gax.CallOption) *TargetHttpProxyIterator { + it := &TargetHttpProxyIterator{} + req = proto.Clone(req).(*computepb.ListRegionTargetHttpProxiesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetHttpProxyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetHttpProxy, string, error) { + resp := &computepb.TargetHttpProxyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetHttpProxies", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetUrlMap changes the URL map for TargetHttpProxy. -func (c *regionTargetHttpProxiesRESTClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionTargetHttpProxiesRESTClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapRegionTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapReferenceResource() jsonReq, err := m.Marshal(body) @@ -416,5 +455,56 @@ func (c *regionTargetHttpProxiesRESTClient) SetUrlMap(ctx context.Context, req * unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// TargetHttpProxyIterator manages a stream of *computepb.TargetHttpProxy. +type TargetHttpProxyIterator struct { + items []*computepb.TargetHttpProxy + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.TargetHttpProxy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetHttpProxyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetHttpProxyIterator) Next() (*computepb.TargetHttpProxy, error) { + var item *computepb.TargetHttpProxy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TargetHttpProxyIterator) bufLen() int { + return len(it.items) +} + +func (it *TargetHttpProxyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/region_target_http_proxies_client_example_test.go b/compute/apiv1/region_target_http_proxies_client_example_test.go index 0ccd58f88ce..0df3051166d 100644 --- a/compute/apiv1/region_target_http_proxies_client_example_test.go +++ b/compute/apiv1/region_target_http_proxies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleRegionTargetHttpProxiesClient_List() { req := &computepb.ListRegionTargetHttpProxiesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionTargetHttpProxiesClient_SetUrlMap() { diff --git a/compute/apiv1/region_target_https_proxies_client.go b/compute/apiv1/region_target_https_proxies_client.go index 6796dc11374..459ba7da980 100644 --- a/compute/apiv1/region_target_https_proxies_client.go +++ b/compute/apiv1/region_target_https_proxies_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionTargetHttpsProxiesClientHook clientHook @@ -51,12 +54,12 @@ type internalRegionTargetHttpsProxiesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.TargetHttpsProxy, error) - Insert(context.Context, *computepb.InsertRegionTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionTargetHttpsProxiesRequest, ...gax.CallOption) (*computepb.TargetHttpsProxyList, error) - SetSslCertificates(context.Context, *computepb.SetSslCertificatesRegionTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetUrlMap(context.Context, *computepb.SetUrlMapRegionTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRegionTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionTargetHttpsProxiesRequest, ...gax.CallOption) *TargetHttpsProxyIterator + SetSslCertificates(context.Context, *computepb.SetSslCertificatesRegionTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) + SetUrlMap(context.Context, *computepb.SetUrlMapRegionTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) } // RegionTargetHttpsProxiesClient is a client for interacting with Google Compute Engine API. @@ -94,7 +97,7 @@ func (c *RegionTargetHttpsProxiesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetHttpsProxy resource. -func (c *RegionTargetHttpsProxiesClient) Delete(ctx context.Context, req *computepb.DeleteRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionTargetHttpsProxiesClient) Delete(ctx context.Context, req *computepb.DeleteRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -104,22 +107,22 @@ func (c *RegionTargetHttpsProxiesClient) Get(ctx context.Context, req *computepb } // Insert creates a TargetHttpsProxy resource in the specified project and region using the data included in the request. -func (c *RegionTargetHttpsProxiesClient) Insert(ctx context.Context, req *computepb.InsertRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionTargetHttpsProxiesClient) Insert(ctx context.Context, req *computepb.InsertRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of TargetHttpsProxy resources available to the specified project in the specified region. -func (c *RegionTargetHttpsProxiesClient) List(ctx context.Context, req *computepb.ListRegionTargetHttpsProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpsProxyList, error) { +func (c *RegionTargetHttpsProxiesClient) List(ctx context.Context, req *computepb.ListRegionTargetHttpsProxiesRequest, opts ...gax.CallOption) *TargetHttpsProxyIterator { return c.internalClient.List(ctx, req, opts...) } // SetSslCertificates replaces SslCertificates for TargetHttpsProxy. -func (c *RegionTargetHttpsProxiesClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionTargetHttpsProxiesClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetSslCertificates(ctx, req, opts...) } // SetUrlMap changes the URL map for TargetHttpsProxy. -func (c *RegionTargetHttpsProxiesClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionTargetHttpsProxiesClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetUrlMap(ctx, req, opts...) } @@ -188,7 +191,7 @@ func (c *regionTargetHttpsProxiesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetHttpsProxy resource. -func (c *regionTargetHttpsProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionTargetHttpsProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetHttpsProxies/%v", req.GetProject(), req.GetRegion(), req.GetTargetHttpsProxy()) @@ -228,7 +231,11 @@ func (c *regionTargetHttpsProxiesRESTClient) Delete(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified TargetHttpsProxy resource in the specified region. Gets a list of available target HTTP proxies by making a list() request. @@ -269,7 +276,7 @@ func (c *regionTargetHttpsProxiesRESTClient) Get(ctx context.Context, req *compu } // Insert creates a TargetHttpsProxy resource in the specified project and region using the data included in the request. -func (c *regionTargetHttpsProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionTargetHttpsProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetHttpsProxyResource() jsonReq, err := m.Marshal(body) @@ -316,67 +323,99 @@ func (c *regionTargetHttpsProxiesRESTClient) Insert(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of TargetHttpsProxy resources available to the specified project in the specified region. -func (c *regionTargetHttpsProxiesRESTClient) List(ctx context.Context, req *computepb.ListRegionTargetHttpsProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpsProxyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetHttpsProxies", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of TargetHttpsProxy resources available to the specified project in the specified region. +func (c *regionTargetHttpsProxiesRESTClient) List(ctx context.Context, req *computepb.ListRegionTargetHttpsProxiesRequest, opts ...gax.CallOption) *TargetHttpsProxyIterator { + it := &TargetHttpsProxyIterator{} + req = proto.Clone(req).(*computepb.ListRegionTargetHttpsProxiesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetHttpsProxyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetHttpsProxy, string, error) { + resp := &computepb.TargetHttpsProxyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetHttpsProxies", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetSslCertificates replaces SslCertificates for TargetHttpsProxy. -func (c *regionTargetHttpsProxiesRESTClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionTargetHttpsProxiesRESTClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionTargetHttpsProxiesSetSslCertificatesRequestResource() jsonReq, err := m.Marshal(body) @@ -423,11 +462,15 @@ func (c *regionTargetHttpsProxiesRESTClient) SetSslCertificates(ctx context.Cont unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetUrlMap changes the URL map for TargetHttpsProxy. -func (c *regionTargetHttpsProxiesRESTClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionTargetHttpsProxiesRESTClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapRegionTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapReferenceResource() jsonReq, err := m.Marshal(body) @@ -474,5 +517,56 @@ func (c *regionTargetHttpsProxiesRESTClient) SetUrlMap(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// TargetHttpsProxyIterator manages a stream of *computepb.TargetHttpsProxy. +type TargetHttpsProxyIterator struct { + items []*computepb.TargetHttpsProxy + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.TargetHttpsProxy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetHttpsProxyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetHttpsProxyIterator) Next() (*computepb.TargetHttpsProxy, error) { + var item *computepb.TargetHttpsProxy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TargetHttpsProxyIterator) bufLen() int { + return len(it.items) +} + +func (it *TargetHttpsProxyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/region_target_https_proxies_client_example_test.go b/compute/apiv1/region_target_https_proxies_client_example_test.go index 2e5ecb82af5..9c3d3a3cec0 100644 --- a/compute/apiv1/region_target_https_proxies_client_example_test.go +++ b/compute/apiv1/region_target_https_proxies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleRegionTargetHttpsProxiesClient_List() { req := &computepb.ListRegionTargetHttpsProxiesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionTargetHttpsProxiesClient_SetSslCertificates() { diff --git a/compute/apiv1/region_url_maps_client.go b/compute/apiv1/region_url_maps_client.go index 4c6388556fd..f7f7dfab743 100644 --- a/compute/apiv1/region_url_maps_client.go +++ b/compute/apiv1/region_url_maps_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionUrlMapsClientHook clientHook @@ -52,12 +55,12 @@ type internalRegionUrlMapsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRegionUrlMapRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRegionUrlMapRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRegionUrlMapRequest, ...gax.CallOption) (*computepb.UrlMap, error) - Insert(context.Context, *computepb.InsertRegionUrlMapRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRegionUrlMapsRequest, ...gax.CallOption) (*computepb.UrlMapList, error) - Patch(context.Context, *computepb.PatchRegionUrlMapRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateRegionUrlMapRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRegionUrlMapRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRegionUrlMapsRequest, ...gax.CallOption) *UrlMapIterator + Patch(context.Context, *computepb.PatchRegionUrlMapRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateRegionUrlMapRequest, ...gax.CallOption) (*Operation, error) Validate(context.Context, *computepb.ValidateRegionUrlMapRequest, ...gax.CallOption) (*computepb.UrlMapsValidateResponse, error) } @@ -96,7 +99,7 @@ func (c *RegionUrlMapsClient) Connection() *grpc.ClientConn { } // Delete deletes the specified UrlMap resource. -func (c *RegionUrlMapsClient) Delete(ctx context.Context, req *computepb.DeleteRegionUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionUrlMapsClient) Delete(ctx context.Context, req *computepb.DeleteRegionUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -106,22 +109,22 @@ func (c *RegionUrlMapsClient) Get(ctx context.Context, req *computepb.GetRegionU } // Insert creates a UrlMap resource in the specified project using the data included in the request. -func (c *RegionUrlMapsClient) Insert(ctx context.Context, req *computepb.InsertRegionUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionUrlMapsClient) Insert(ctx context.Context, req *computepb.InsertRegionUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of UrlMap resources available to the specified project in the specified region. -func (c *RegionUrlMapsClient) List(ctx context.Context, req *computepb.ListRegionUrlMapsRequest, opts ...gax.CallOption) (*computepb.UrlMapList, error) { +func (c *RegionUrlMapsClient) List(ctx context.Context, req *computepb.ListRegionUrlMapsRequest, opts ...gax.CallOption) *UrlMapIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified UrlMap resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *RegionUrlMapsClient) Patch(ctx context.Context, req *computepb.PatchRegionUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionUrlMapsClient) Patch(ctx context.Context, req *computepb.PatchRegionUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // Update updates the specified UrlMap resource with the data included in the request. -func (c *RegionUrlMapsClient) Update(ctx context.Context, req *computepb.UpdateRegionUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RegionUrlMapsClient) Update(ctx context.Context, req *computepb.UpdateRegionUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -195,7 +198,7 @@ func (c *regionUrlMapsRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified UrlMap resource. -func (c *regionUrlMapsRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionUrlMapsRESTClient) Delete(ctx context.Context, req *computepb.DeleteRegionUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/urlMaps/%v", req.GetProject(), req.GetRegion(), req.GetUrlMap()) @@ -235,7 +238,11 @@ func (c *regionUrlMapsRESTClient) Delete(ctx context.Context, req *computepb.Del unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified UrlMap resource. Gets a list of available URL maps by making a list() request. @@ -276,7 +283,7 @@ func (c *regionUrlMapsRESTClient) Get(ctx context.Context, req *computepb.GetReg } // Insert creates a UrlMap resource in the specified project using the data included in the request. -func (c *regionUrlMapsRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionUrlMapsRESTClient) Insert(ctx context.Context, req *computepb.InsertRegionUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapResource() jsonReq, err := m.Marshal(body) @@ -323,67 +330,99 @@ func (c *regionUrlMapsRESTClient) Insert(ctx context.Context, req *computepb.Ins unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of UrlMap resources available to the specified project in the specified region. -func (c *regionUrlMapsRESTClient) List(ctx context.Context, req *computepb.ListRegionUrlMapsRequest, opts ...gax.CallOption) (*computepb.UrlMapList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/urlMaps", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of UrlMap resources available to the specified project in the specified region. +func (c *regionUrlMapsRESTClient) List(ctx context.Context, req *computepb.ListRegionUrlMapsRequest, opts ...gax.CallOption) *UrlMapIterator { + it := &UrlMapIterator{} + req = proto.Clone(req).(*computepb.ListRegionUrlMapsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.UrlMapList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.UrlMap, string, error) { + resp := &computepb.UrlMapList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/urlMaps", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified UrlMap resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *regionUrlMapsRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionUrlMapsRESTClient) Patch(ctx context.Context, req *computepb.PatchRegionUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapResource() jsonReq, err := m.Marshal(body) @@ -430,11 +469,15 @@ func (c *regionUrlMapsRESTClient) Patch(ctx context.Context, req *computepb.Patc unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates the specified UrlMap resource with the data included in the request. -func (c *regionUrlMapsRESTClient) Update(ctx context.Context, req *computepb.UpdateRegionUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *regionUrlMapsRESTClient) Update(ctx context.Context, req *computepb.UpdateRegionUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapResource() jsonReq, err := m.Marshal(body) @@ -481,7 +524,11 @@ func (c *regionUrlMapsRESTClient) Update(ctx context.Context, req *computepb.Upd unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Validate runs static validation for the UrlMap. In particular, the tests of the provided UrlMap will be run. Calling this method does NOT create the UrlMap. @@ -527,3 +574,50 @@ func (c *regionUrlMapsRESTClient) Validate(ctx context.Context, req *computepb.V return rsp, unm.Unmarshal(buf, rsp) } + +// UrlMapIterator manages a stream of *computepb.UrlMap. +type UrlMapIterator struct { + items []*computepb.UrlMap + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.UrlMap, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *UrlMapIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *UrlMapIterator) Next() (*computepb.UrlMap, error) { + var item *computepb.UrlMap + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *UrlMapIterator) bufLen() int { + return len(it.items) +} + +func (it *UrlMapIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/region_url_maps_client_example_test.go b/compute/apiv1/region_url_maps_client_example_test.go index 8a20f726251..56834642f6c 100644 --- a/compute/apiv1/region_url_maps_client_example_test.go +++ b/compute/apiv1/region_url_maps_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleRegionUrlMapsClient_List() { req := &computepb.ListRegionUrlMapsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRegionUrlMapsClient_Patch() { diff --git a/compute/apiv1/regions_client.go b/compute/apiv1/regions_client.go index ed40dc247c9..9247c52e0a8 100644 --- a/compute/apiv1/regions_client.go +++ b/compute/apiv1/regions_client.go @@ -20,10 +20,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +33,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRegionsClientHook clientHook @@ -47,7 +50,7 @@ type internalRegionsClient interface { setGoogleClientInfo(...string) Connection() *grpc.ClientConn Get(context.Context, *computepb.GetRegionRequest, ...gax.CallOption) (*computepb.Region, error) - List(context.Context, *computepb.ListRegionsRequest, ...gax.CallOption) (*computepb.RegionList, error) + List(context.Context, *computepb.ListRegionsRequest, ...gax.CallOption) *RegionIterator } // RegionsClient is a client for interacting with Google Compute Engine API. @@ -90,7 +93,7 @@ func (c *RegionsClient) Get(ctx context.Context, req *computepb.GetRegionRequest } // List retrieves the list of region resources available to the specified project. -func (c *RegionsClient) List(ctx context.Context, req *computepb.ListRegionsRequest, opts ...gax.CallOption) (*computepb.RegionList, error) { +func (c *RegionsClient) List(ctx context.Context, req *computepb.ListRegionsRequest, opts ...gax.CallOption) *RegionIterator { return c.internalClient.List(ctx, req, opts...) } @@ -196,57 +199,132 @@ func (c *regionsRESTClient) Get(ctx context.Context, req *computepb.GetRegionReq } // List retrieves the list of region resources available to the specified project. -func (c *regionsRESTClient) List(ctx context.Context, req *computepb.ListRegionsRequest, opts ...gax.CallOption) (*computepb.RegionList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *regionsRESTClient) List(ctx context.Context, req *computepb.ListRegionsRequest, opts ...gax.CallOption) *RegionIterator { + it := &RegionIterator{} + req = proto.Clone(req).(*computepb.ListRegionsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Region, string, error) { + resp := &computepb.RegionList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// RegionIterator manages a stream of *computepb.Region. +type RegionIterator struct { + items []*computepb.Region + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Region, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *RegionIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *RegionIterator) Next() (*computepb.Region, error) { + var item *computepb.Region + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RegionList{} +func (it *RegionIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *RegionIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/regions_client_example_test.go b/compute/apiv1/regions_client_example_test.go index 80af1fd0722..a30366a4235 100644 --- a/compute/apiv1/regions_client_example_test.go +++ b/compute/apiv1/regions_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,10 +66,16 @@ func ExampleRegionsClient_List() { req := &computepb.ListRegionsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/reservations_client.go b/compute/apiv1/reservations_client.go index 890808f9dc5..6b0e2deb586 100644 --- a/compute/apiv1/reservations_client.go +++ b/compute/apiv1/reservations_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newReservationsClientHook clientHook @@ -54,13 +58,13 @@ type internalReservationsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListReservationsRequest, ...gax.CallOption) (*computepb.ReservationAggregatedList, error) - Delete(context.Context, *computepb.DeleteReservationRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListReservationsRequest, ...gax.CallOption) *ReservationsScopedListPairIterator + Delete(context.Context, *computepb.DeleteReservationRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetReservationRequest, ...gax.CallOption) (*computepb.Reservation, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyReservationRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertReservationRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListReservationsRequest, ...gax.CallOption) (*computepb.ReservationList, error) - Resize(context.Context, *computepb.ResizeReservationRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertReservationRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListReservationsRequest, ...gax.CallOption) *ReservationIterator + Resize(context.Context, *computepb.ResizeReservationRequest, ...gax.CallOption) (*Operation, error) SetIamPolicy(context.Context, *computepb.SetIamPolicyReservationRequest, ...gax.CallOption) (*computepb.Policy, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsReservationRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -100,12 +104,12 @@ func (c *ReservationsClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of reservations. -func (c *ReservationsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListReservationsRequest, opts ...gax.CallOption) (*computepb.ReservationAggregatedList, error) { +func (c *ReservationsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListReservationsRequest, opts ...gax.CallOption) *ReservationsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified reservation. -func (c *ReservationsClient) Delete(ctx context.Context, req *computepb.DeleteReservationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ReservationsClient) Delete(ctx context.Context, req *computepb.DeleteReservationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -120,17 +124,17 @@ func (c *ReservationsClient) GetIamPolicy(ctx context.Context, req *computepb.Ge } // Insert creates a new reservation. For more information, read Reserving zonal resources. -func (c *ReservationsClient) Insert(ctx context.Context, req *computepb.InsertReservationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ReservationsClient) Insert(ctx context.Context, req *computepb.InsertReservationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List a list of all the reservations that have been configured for the specified project in specified zone. -func (c *ReservationsClient) List(ctx context.Context, req *computepb.ListReservationsRequest, opts ...gax.CallOption) (*computepb.ReservationList, error) { +func (c *ReservationsClient) List(ctx context.Context, req *computepb.ListReservationsRequest, opts ...gax.CallOption) *ReservationIterator { return c.internalClient.List(ctx, req, opts...) } // Resize resizes the reservation (applicable to standalone reservations only). For more information, read Modifying reservations. -func (c *ReservationsClient) Resize(ctx context.Context, req *computepb.ResizeReservationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ReservationsClient) Resize(ctx context.Context, req *computepb.ResizeReservationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Resize(ctx, req, opts...) } @@ -209,66 +213,101 @@ func (c *reservationsRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of reservations. -func (c *reservationsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListReservationsRequest, opts ...gax.CallOption) (*computepb.ReservationAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/reservations", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *reservationsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListReservationsRequest, opts ...gax.CallOption) *ReservationsScopedListPairIterator { + it := &ReservationsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListReservationsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ReservationAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]ReservationsScopedListPair, string, error) { + resp := &computepb.ReservationAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/reservations", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]ReservationsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, ReservationsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified reservation. -func (c *reservationsRESTClient) Delete(ctx context.Context, req *computepb.DeleteReservationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *reservationsRESTClient) Delete(ctx context.Context, req *computepb.DeleteReservationRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/reservations/%v", req.GetProject(), req.GetZone(), req.GetReservation()) @@ -308,7 +347,11 @@ func (c *reservationsRESTClient) Delete(ctx context.Context, req *computepb.Dele unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get retrieves information about the specified reservation. @@ -393,7 +436,7 @@ func (c *reservationsRESTClient) GetIamPolicy(ctx context.Context, req *computep } // Insert creates a new reservation. For more information, read Reserving zonal resources. -func (c *reservationsRESTClient) Insert(ctx context.Context, req *computepb.InsertReservationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *reservationsRESTClient) Insert(ctx context.Context, req *computepb.InsertReservationRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetReservationResource() jsonReq, err := m.Marshal(body) @@ -440,67 +483,99 @@ func (c *reservationsRESTClient) Insert(ctx context.Context, req *computepb.Inse unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List a list of all the reservations that have been configured for the specified project in specified zone. -func (c *reservationsRESTClient) List(ctx context.Context, req *computepb.ListReservationsRequest, opts ...gax.CallOption) (*computepb.ReservationList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/reservations", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List a list of all the reservations that have been configured for the specified project in specified zone. +func (c *reservationsRESTClient) List(ctx context.Context, req *computepb.ListReservationsRequest, opts ...gax.CallOption) *ReservationIterator { + it := &ReservationIterator{} + req = proto.Clone(req).(*computepb.ListReservationsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ReservationList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Reservation, string, error) { + resp := &computepb.ReservationList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/reservations", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Resize resizes the reservation (applicable to standalone reservations only). For more information, read Modifying reservations. -func (c *reservationsRESTClient) Resize(ctx context.Context, req *computepb.ResizeReservationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *reservationsRESTClient) Resize(ctx context.Context, req *computepb.ResizeReservationRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetReservationsResizeRequestResource() jsonReq, err := m.Marshal(body) @@ -547,7 +622,11 @@ func (c *reservationsRESTClient) Resize(ctx context.Context, req *computepb.Resi unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -637,3 +716,103 @@ func (c *reservationsRESTClient) TestIamPermissions(ctx context.Context, req *co return rsp, unm.Unmarshal(buf, rsp) } + +// ReservationIterator manages a stream of *computepb.Reservation. +type ReservationIterator struct { + items []*computepb.Reservation + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Reservation, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ReservationIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ReservationIterator) Next() (*computepb.Reservation, error) { + var item *computepb.Reservation + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ReservationIterator) bufLen() int { + return len(it.items) +} + +func (it *ReservationIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ReservationsScopedListPair is a holder type for string/*computepb.ReservationsScopedList map entries +type ReservationsScopedListPair struct { + Key string + Value *computepb.ReservationsScopedList +} + +// ReservationsScopedListPairIterator manages a stream of ReservationsScopedListPair. +type ReservationsScopedListPairIterator struct { + items []ReservationsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []ReservationsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ReservationsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ReservationsScopedListPairIterator) Next() (ReservationsScopedListPair, error) { + var item ReservationsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ReservationsScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *ReservationsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/reservations_client_example_test.go b/compute/apiv1/reservations_client_example_test.go index dda54366096..07b0284c40e 100644 --- a/compute/apiv1/reservations_client_example_test.go +++ b/compute/apiv1/reservations_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleReservationsClient_AggregatedList() { req := &computepb.AggregatedListReservationsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleReservationsClient_Delete() { @@ -141,12 +148,18 @@ func ExampleReservationsClient_List() { req := &computepb.ListReservationsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleReservationsClient_Resize() { diff --git a/compute/apiv1/resource_policies_client.go b/compute/apiv1/resource_policies_client.go index 68892df8223..0ec1aa9e84c 100644 --- a/compute/apiv1/resource_policies_client.go +++ b/compute/apiv1/resource_policies_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newResourcePoliciesClientHook clientHook @@ -53,12 +57,12 @@ type internalResourcePoliciesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListResourcePoliciesRequest, ...gax.CallOption) (*computepb.ResourcePolicyAggregatedList, error) - Delete(context.Context, *computepb.DeleteResourcePolicyRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListResourcePoliciesRequest, ...gax.CallOption) *ResourcePoliciesScopedListPairIterator + Delete(context.Context, *computepb.DeleteResourcePolicyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetResourcePolicyRequest, ...gax.CallOption) (*computepb.ResourcePolicy, error) GetIamPolicy(context.Context, *computepb.GetIamPolicyResourcePolicyRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertResourcePolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListResourcePoliciesRequest, ...gax.CallOption) (*computepb.ResourcePolicyList, error) + Insert(context.Context, *computepb.InsertResourcePolicyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListResourcePoliciesRequest, ...gax.CallOption) *ResourcePolicyIterator SetIamPolicy(context.Context, *computepb.SetIamPolicyResourcePolicyRequest, ...gax.CallOption) (*computepb.Policy, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsResourcePolicyRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -98,12 +102,12 @@ func (c *ResourcePoliciesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of resource policies. -func (c *ResourcePoliciesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListResourcePoliciesRequest, opts ...gax.CallOption) (*computepb.ResourcePolicyAggregatedList, error) { +func (c *ResourcePoliciesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListResourcePoliciesRequest, opts ...gax.CallOption) *ResourcePoliciesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified resource policy. -func (c *ResourcePoliciesClient) Delete(ctx context.Context, req *computepb.DeleteResourcePolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ResourcePoliciesClient) Delete(ctx context.Context, req *computepb.DeleteResourcePolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -118,12 +122,12 @@ func (c *ResourcePoliciesClient) GetIamPolicy(ctx context.Context, req *computep } // Insert creates a new resource policy. -func (c *ResourcePoliciesClient) Insert(ctx context.Context, req *computepb.InsertResourcePolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ResourcePoliciesClient) Insert(ctx context.Context, req *computepb.InsertResourcePolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List a list all the resource policies that have been configured for the specified project in specified region. -func (c *ResourcePoliciesClient) List(ctx context.Context, req *computepb.ListResourcePoliciesRequest, opts ...gax.CallOption) (*computepb.ResourcePolicyList, error) { +func (c *ResourcePoliciesClient) List(ctx context.Context, req *computepb.ListResourcePoliciesRequest, opts ...gax.CallOption) *ResourcePolicyIterator { return c.internalClient.List(ctx, req, opts...) } @@ -202,66 +206,101 @@ func (c *resourcePoliciesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of resource policies. -func (c *resourcePoliciesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListResourcePoliciesRequest, opts ...gax.CallOption) (*computepb.ResourcePolicyAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/resourcePolicies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *resourcePoliciesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListResourcePoliciesRequest, opts ...gax.CallOption) *ResourcePoliciesScopedListPairIterator { + it := &ResourcePoliciesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListResourcePoliciesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ResourcePolicyAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]ResourcePoliciesScopedListPair, string, error) { + resp := &computepb.ResourcePolicyAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/resourcePolicies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]ResourcePoliciesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, ResourcePoliciesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified resource policy. -func (c *resourcePoliciesRESTClient) Delete(ctx context.Context, req *computepb.DeleteResourcePolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *resourcePoliciesRESTClient) Delete(ctx context.Context, req *computepb.DeleteResourcePolicyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/resourcePolicies/%v", req.GetProject(), req.GetRegion(), req.GetResourcePolicy()) @@ -301,7 +340,11 @@ func (c *resourcePoliciesRESTClient) Delete(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get retrieves all information of the specified resource policy. @@ -386,7 +429,7 @@ func (c *resourcePoliciesRESTClient) GetIamPolicy(ctx context.Context, req *comp } // Insert creates a new resource policy. -func (c *resourcePoliciesRESTClient) Insert(ctx context.Context, req *computepb.InsertResourcePolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *resourcePoliciesRESTClient) Insert(ctx context.Context, req *computepb.InsertResourcePolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetResourcePolicyResource() jsonReq, err := m.Marshal(body) @@ -433,63 +476,95 @@ func (c *resourcePoliciesRESTClient) Insert(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List a list all the resource policies that have been configured for the specified project in specified region. -func (c *resourcePoliciesRESTClient) List(ctx context.Context, req *computepb.ListResourcePoliciesRequest, opts ...gax.CallOption) (*computepb.ResourcePolicyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/resourcePolicies", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List a list all the resource policies that have been configured for the specified project in specified region. +func (c *resourcePoliciesRESTClient) List(ctx context.Context, req *computepb.ListResourcePoliciesRequest, opts ...gax.CallOption) *ResourcePolicyIterator { + it := &ResourcePolicyIterator{} + req = proto.Clone(req).(*computepb.ListResourcePoliciesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ResourcePolicyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.ResourcePolicy, string, error) { + resp := &computepb.ResourcePolicyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/resourcePolicies", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -579,3 +654,103 @@ func (c *resourcePoliciesRESTClient) TestIamPermissions(ctx context.Context, req return rsp, unm.Unmarshal(buf, rsp) } + +// ResourcePoliciesScopedListPair is a holder type for string/*computepb.ResourcePoliciesScopedList map entries +type ResourcePoliciesScopedListPair struct { + Key string + Value *computepb.ResourcePoliciesScopedList +} + +// ResourcePoliciesScopedListPairIterator manages a stream of ResourcePoliciesScopedListPair. +type ResourcePoliciesScopedListPairIterator struct { + items []ResourcePoliciesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []ResourcePoliciesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ResourcePoliciesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ResourcePoliciesScopedListPairIterator) Next() (ResourcePoliciesScopedListPair, error) { + var item ResourcePoliciesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ResourcePoliciesScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *ResourcePoliciesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// ResourcePolicyIterator manages a stream of *computepb.ResourcePolicy. +type ResourcePolicyIterator struct { + items []*computepb.ResourcePolicy + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.ResourcePolicy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ResourcePolicyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ResourcePolicyIterator) Next() (*computepb.ResourcePolicy, error) { + var item *computepb.ResourcePolicy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *ResourcePolicyIterator) bufLen() int { + return len(it.items) +} + +func (it *ResourcePolicyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/resource_policies_client_example_test.go b/compute/apiv1/resource_policies_client_example_test.go index 361e180ee6e..534e16193c4 100644 --- a/compute/apiv1/resource_policies_client_example_test.go +++ b/compute/apiv1/resource_policies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleResourcePoliciesClient_AggregatedList() { req := &computepb.AggregatedListResourcePoliciesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleResourcePoliciesClient_Delete() { @@ -141,12 +148,18 @@ func ExampleResourcePoliciesClient_List() { req := &computepb.ListResourcePoliciesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleResourcePoliciesClient_SetIamPolicy() { diff --git a/compute/apiv1/routers_client.go b/compute/apiv1/routers_client.go index d5d0f947e82..32f64b00111 100644 --- a/compute/apiv1/routers_client.go +++ b/compute/apiv1/routers_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRoutersClientHook clientHook @@ -55,16 +59,16 @@ type internalRoutersClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListRoutersRequest, ...gax.CallOption) (*computepb.RouterAggregatedList, error) - Delete(context.Context, *computepb.DeleteRouterRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListRoutersRequest, ...gax.CallOption) *RoutersScopedListPairIterator + Delete(context.Context, *computepb.DeleteRouterRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRouterRequest, ...gax.CallOption) (*computepb.Router, error) - GetNatMappingInfo(context.Context, *computepb.GetNatMappingInfoRoutersRequest, ...gax.CallOption) (*computepb.VmEndpointNatMappingsList, error) + GetNatMappingInfo(context.Context, *computepb.GetNatMappingInfoRoutersRequest, ...gax.CallOption) *VmEndpointNatMappingsIterator GetRouterStatus(context.Context, *computepb.GetRouterStatusRouterRequest, ...gax.CallOption) (*computepb.RouterStatusResponse, error) - Insert(context.Context, *computepb.InsertRouterRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRoutersRequest, ...gax.CallOption) (*computepb.RouterList, error) - Patch(context.Context, *computepb.PatchRouterRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertRouterRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRoutersRequest, ...gax.CallOption) *RouterIterator + Patch(context.Context, *computepb.PatchRouterRequest, ...gax.CallOption) (*Operation, error) Preview(context.Context, *computepb.PreviewRouterRequest, ...gax.CallOption) (*computepb.RoutersPreviewResponse, error) - Update(context.Context, *computepb.UpdateRouterRequest, ...gax.CallOption) (*computepb.Operation, error) + Update(context.Context, *computepb.UpdateRouterRequest, ...gax.CallOption) (*Operation, error) } // RoutersClient is a client for interacting with Google Compute Engine API. @@ -102,12 +106,12 @@ func (c *RoutersClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of routers. -func (c *RoutersClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListRoutersRequest, opts ...gax.CallOption) (*computepb.RouterAggregatedList, error) { +func (c *RoutersClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListRoutersRequest, opts ...gax.CallOption) *RoutersScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified Router resource. -func (c *RoutersClient) Delete(ctx context.Context, req *computepb.DeleteRouterRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RoutersClient) Delete(ctx context.Context, req *computepb.DeleteRouterRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -117,7 +121,7 @@ func (c *RoutersClient) Get(ctx context.Context, req *computepb.GetRouterRequest } // GetNatMappingInfo retrieves runtime Nat mapping information of VM endpoints. -func (c *RoutersClient) GetNatMappingInfo(ctx context.Context, req *computepb.GetNatMappingInfoRoutersRequest, opts ...gax.CallOption) (*computepb.VmEndpointNatMappingsList, error) { +func (c *RoutersClient) GetNatMappingInfo(ctx context.Context, req *computepb.GetNatMappingInfoRoutersRequest, opts ...gax.CallOption) *VmEndpointNatMappingsIterator { return c.internalClient.GetNatMappingInfo(ctx, req, opts...) } @@ -127,17 +131,17 @@ func (c *RoutersClient) GetRouterStatus(ctx context.Context, req *computepb.GetR } // Insert creates a Router resource in the specified project and region using the data included in the request. -func (c *RoutersClient) Insert(ctx context.Context, req *computepb.InsertRouterRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RoutersClient) Insert(ctx context.Context, req *computepb.InsertRouterRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of Router resources available to the specified project. -func (c *RoutersClient) List(ctx context.Context, req *computepb.ListRoutersRequest, opts ...gax.CallOption) (*computepb.RouterList, error) { +func (c *RoutersClient) List(ctx context.Context, req *computepb.ListRoutersRequest, opts ...gax.CallOption) *RouterIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified Router resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *RoutersClient) Patch(ctx context.Context, req *computepb.PatchRouterRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RoutersClient) Patch(ctx context.Context, req *computepb.PatchRouterRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -147,7 +151,7 @@ func (c *RoutersClient) Preview(ctx context.Context, req *computepb.PreviewRoute } // Update updates the specified Router resource with the data included in the request. This method conforms to PUT semantics, which requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. -func (c *RoutersClient) Update(ctx context.Context, req *computepb.UpdateRouterRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RoutersClient) Update(ctx context.Context, req *computepb.UpdateRouterRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -216,66 +220,101 @@ func (c *routersRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of routers. -func (c *routersRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListRoutersRequest, opts ...gax.CallOption) (*computepb.RouterAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/routers", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *routersRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListRoutersRequest, opts ...gax.CallOption) *RoutersScopedListPairIterator { + it := &RoutersScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListRoutersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RouterAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]RoutersScopedListPair, string, error) { + resp := &computepb.RouterAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/routers", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]RoutersScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, RoutersScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified Router resource. -func (c *routersRESTClient) Delete(ctx context.Context, req *computepb.DeleteRouterRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *routersRESTClient) Delete(ctx context.Context, req *computepb.DeleteRouterRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/routers/%v", req.GetProject(), req.GetRegion(), req.GetRouter()) @@ -315,7 +354,11 @@ func (c *routersRESTClient) Delete(ctx context.Context, req *computepb.DeleteRou unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified Router resource. Gets a list of available routers by making a list() request. @@ -356,59 +399,87 @@ func (c *routersRESTClient) Get(ctx context.Context, req *computepb.GetRouterReq } // GetNatMappingInfo retrieves runtime Nat mapping information of VM endpoints. -func (c *routersRESTClient) GetNatMappingInfo(ctx context.Context, req *computepb.GetNatMappingInfoRoutersRequest, opts ...gax.CallOption) (*computepb.VmEndpointNatMappingsList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/routers/%v/getNatMappingInfo", req.GetProject(), req.GetRegion(), req.GetRouter()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *routersRESTClient) GetNatMappingInfo(ctx context.Context, req *computepb.GetNatMappingInfoRoutersRequest, opts ...gax.CallOption) *VmEndpointNatMappingsIterator { + it := &VmEndpointNatMappingsIterator{} + req = proto.Clone(req).(*computepb.GetNatMappingInfoRoutersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.VmEndpointNatMappingsList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.VmEndpointNatMappings, string, error) { + resp := &computepb.VmEndpointNatMappingsList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/routers/%v/getNatMappingInfo", req.GetProject(), req.GetRegion(), req.GetRouter()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetResult(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // GetRouterStatus retrieves runtime information of the specified router. @@ -449,7 +520,7 @@ func (c *routersRESTClient) GetRouterStatus(ctx context.Context, req *computepb. } // Insert creates a Router resource in the specified project and region using the data included in the request. -func (c *routersRESTClient) Insert(ctx context.Context, req *computepb.InsertRouterRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *routersRESTClient) Insert(ctx context.Context, req *computepb.InsertRouterRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRouterResource() jsonReq, err := m.Marshal(body) @@ -496,67 +567,99 @@ func (c *routersRESTClient) Insert(ctx context.Context, req *computepb.InsertRou unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of Router resources available to the specified project. -func (c *routersRESTClient) List(ctx context.Context, req *computepb.ListRoutersRequest, opts ...gax.CallOption) (*computepb.RouterList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/routers", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of Router resources available to the specified project. +func (c *routersRESTClient) List(ctx context.Context, req *computepb.ListRoutersRequest, opts ...gax.CallOption) *RouterIterator { + it := &RouterIterator{} + req = proto.Clone(req).(*computepb.ListRoutersRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RouterList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Router, string, error) { + resp := &computepb.RouterList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/routers", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified Router resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *routersRESTClient) Patch(ctx context.Context, req *computepb.PatchRouterRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *routersRESTClient) Patch(ctx context.Context, req *computepb.PatchRouterRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRouterResource() jsonReq, err := m.Marshal(body) @@ -603,7 +706,11 @@ func (c *routersRESTClient) Patch(ctx context.Context, req *computepb.PatchRoute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Preview preview fields auto-generated during router create and update operations. Calling this method does NOT create or update the router. @@ -651,7 +758,7 @@ func (c *routersRESTClient) Preview(ctx context.Context, req *computepb.PreviewR } // Update updates the specified Router resource with the data included in the request. This method conforms to PUT semantics, which requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload. -func (c *routersRESTClient) Update(ctx context.Context, req *computepb.UpdateRouterRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *routersRESTClient) Update(ctx context.Context, req *computepb.UpdateRouterRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRouterResource() jsonReq, err := m.Marshal(body) @@ -698,5 +805,156 @@ func (c *routersRESTClient) Update(ctx context.Context, req *computepb.UpdateRou unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// RouterIterator manages a stream of *computepb.Router. +type RouterIterator struct { + items []*computepb.Router + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Router, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *RouterIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *RouterIterator) Next() (*computepb.Router, error) { + var item *computepb.Router + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *RouterIterator) bufLen() int { + return len(it.items) +} + +func (it *RouterIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// RoutersScopedListPair is a holder type for string/*computepb.RoutersScopedList map entries +type RoutersScopedListPair struct { + Key string + Value *computepb.RoutersScopedList +} + +// RoutersScopedListPairIterator manages a stream of RoutersScopedListPair. +type RoutersScopedListPairIterator struct { + items []RoutersScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []RoutersScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *RoutersScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *RoutersScopedListPairIterator) Next() (RoutersScopedListPair, error) { + var item RoutersScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *RoutersScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *RoutersScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// VmEndpointNatMappingsIterator manages a stream of *computepb.VmEndpointNatMappings. +type VmEndpointNatMappingsIterator struct { + items []*computepb.VmEndpointNatMappings + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.VmEndpointNatMappings, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *VmEndpointNatMappingsIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *VmEndpointNatMappingsIterator) Next() (*computepb.VmEndpointNatMappings, error) { + var item *computepb.VmEndpointNatMappings + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *VmEndpointNatMappingsIterator) bufLen() int { + return len(it.items) +} + +func (it *VmEndpointNatMappingsIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/routers_client_example_test.go b/compute/apiv1/routers_client_example_test.go index 96553d9bd1d..fbccb531efd 100644 --- a/compute/apiv1/routers_client_example_test.go +++ b/compute/apiv1/routers_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleRoutersClient_AggregatedList() { req := &computepb.AggregatedListRoutersRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRoutersClient_Delete() { @@ -103,12 +110,18 @@ func ExampleRoutersClient_GetNatMappingInfo() { req := &computepb.GetNatMappingInfoRoutersRequest{ // TODO: Fill request struct fields. } - resp, err := c.GetNatMappingInfo(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.GetNatMappingInfo(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRoutersClient_GetRouterStatus() { @@ -160,12 +173,18 @@ func ExampleRoutersClient_List() { req := &computepb.ListRoutersRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleRoutersClient_Patch() { diff --git a/compute/apiv1/routes_client.go b/compute/apiv1/routes_client.go index 129987d8e9d..0ad2dd763b5 100644 --- a/compute/apiv1/routes_client.go +++ b/compute/apiv1/routes_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newRoutesClientHook clientHook @@ -49,10 +52,10 @@ type internalRoutesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteRouteRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteRouteRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetRouteRequest, ...gax.CallOption) (*computepb.Route, error) - Insert(context.Context, *computepb.InsertRouteRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListRoutesRequest, ...gax.CallOption) (*computepb.RouteList, error) + Insert(context.Context, *computepb.InsertRouteRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListRoutesRequest, ...gax.CallOption) *RouteIterator } // RoutesClient is a client for interacting with Google Compute Engine API. @@ -90,7 +93,7 @@ func (c *RoutesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified Route resource. -func (c *RoutesClient) Delete(ctx context.Context, req *computepb.DeleteRouteRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RoutesClient) Delete(ctx context.Context, req *computepb.DeleteRouteRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -100,12 +103,12 @@ func (c *RoutesClient) Get(ctx context.Context, req *computepb.GetRouteRequest, } // Insert creates a Route resource in the specified project using the data included in the request. -func (c *RoutesClient) Insert(ctx context.Context, req *computepb.InsertRouteRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *RoutesClient) Insert(ctx context.Context, req *computepb.InsertRouteRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of Route resources available to the specified project. -func (c *RoutesClient) List(ctx context.Context, req *computepb.ListRoutesRequest, opts ...gax.CallOption) (*computepb.RouteList, error) { +func (c *RoutesClient) List(ctx context.Context, req *computepb.ListRoutesRequest, opts ...gax.CallOption) *RouteIterator { return c.internalClient.List(ctx, req, opts...) } @@ -174,7 +177,7 @@ func (c *routesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified Route resource. -func (c *routesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRouteRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *routesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRouteRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/routes/%v", req.GetProject(), req.GetRoute()) @@ -214,7 +217,11 @@ func (c *routesRESTClient) Delete(ctx context.Context, req *computepb.DeleteRout unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified Route resource. Gets a list of available routes by making a list() request. @@ -255,7 +262,7 @@ func (c *routesRESTClient) Get(ctx context.Context, req *computepb.GetRouteReque } // Insert creates a Route resource in the specified project using the data included in the request. -func (c *routesRESTClient) Insert(ctx context.Context, req *computepb.InsertRouteRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *routesRESTClient) Insert(ctx context.Context, req *computepb.InsertRouteRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRouteResource() jsonReq, err := m.Marshal(body) @@ -302,61 +309,140 @@ func (c *routesRESTClient) Insert(ctx context.Context, req *computepb.InsertRout unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List retrieves the list of Route resources available to the specified project. -func (c *routesRESTClient) List(ctx context.Context, req *computepb.ListRoutesRequest, opts ...gax.CallOption) (*computepb.RouteList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/routes", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *routesRESTClient) List(ctx context.Context, req *computepb.ListRoutesRequest, opts ...gax.CallOption) *RouteIterator { + it := &RouteIterator{} + req = proto.Clone(req).(*computepb.ListRoutesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Route, string, error) { + resp := &computepb.RouteList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/routes", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// RouteIterator manages a stream of *computepb.Route. +type RouteIterator struct { + items []*computepb.Route + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Route, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *RouteIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *RouteIterator) Next() (*computepb.Route, error) { + var item *computepb.Route + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.RouteList{} +func (it *RouteIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *RouteIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/routes_client_example_test.go b/compute/apiv1/routes_client_example_test.go index 730354784ea..9a05fe2b215 100644 --- a/compute/apiv1/routes_client_example_test.go +++ b/compute/apiv1/routes_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,10 +104,16 @@ func ExampleRoutesClient_List() { req := &computepb.ListRoutesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/security_policies_client.go b/compute/apiv1/security_policies_client.go index 83e56c14b34..a02f28e385b 100644 --- a/compute/apiv1/security_policies_client.go +++ b/compute/apiv1/security_policies_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newSecurityPoliciesClientHook clientHook @@ -55,16 +58,16 @@ type internalSecurityPoliciesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddRule(context.Context, *computepb.AddRuleSecurityPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - Delete(context.Context, *computepb.DeleteSecurityPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) + AddRule(context.Context, *computepb.AddRuleSecurityPolicyRequest, ...gax.CallOption) (*Operation, error) + Delete(context.Context, *computepb.DeleteSecurityPolicyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetSecurityPolicyRequest, ...gax.CallOption) (*computepb.SecurityPolicy, error) GetRule(context.Context, *computepb.GetRuleSecurityPolicyRequest, ...gax.CallOption) (*computepb.SecurityPolicyRule, error) - Insert(context.Context, *computepb.InsertSecurityPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListSecurityPoliciesRequest, ...gax.CallOption) (*computepb.SecurityPolicyList, error) + Insert(context.Context, *computepb.InsertSecurityPolicyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListSecurityPoliciesRequest, ...gax.CallOption) *SecurityPolicyIterator ListPreconfiguredExpressionSets(context.Context, *computepb.ListPreconfiguredExpressionSetsSecurityPoliciesRequest, ...gax.CallOption) (*computepb.SecurityPoliciesListPreconfiguredExpressionSetsResponse, error) - Patch(context.Context, *computepb.PatchSecurityPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - PatchRule(context.Context, *computepb.PatchRuleSecurityPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - RemoveRule(context.Context, *computepb.RemoveRuleSecurityPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) + Patch(context.Context, *computepb.PatchSecurityPolicyRequest, ...gax.CallOption) (*Operation, error) + PatchRule(context.Context, *computepb.PatchRuleSecurityPolicyRequest, ...gax.CallOption) (*Operation, error) + RemoveRule(context.Context, *computepb.RemoveRuleSecurityPolicyRequest, ...gax.CallOption) (*Operation, error) } // SecurityPoliciesClient is a client for interacting with Google Compute Engine API. @@ -102,12 +105,12 @@ func (c *SecurityPoliciesClient) Connection() *grpc.ClientConn { } // AddRule inserts a rule into a security policy. -func (c *SecurityPoliciesClient) AddRule(ctx context.Context, req *computepb.AddRuleSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SecurityPoliciesClient) AddRule(ctx context.Context, req *computepb.AddRuleSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddRule(ctx, req, opts...) } // Delete deletes the specified policy. -func (c *SecurityPoliciesClient) Delete(ctx context.Context, req *computepb.DeleteSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SecurityPoliciesClient) Delete(ctx context.Context, req *computepb.DeleteSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -122,12 +125,12 @@ func (c *SecurityPoliciesClient) GetRule(ctx context.Context, req *computepb.Get } // Insert creates a new policy in the specified project using the data included in the request. -func (c *SecurityPoliciesClient) Insert(ctx context.Context, req *computepb.InsertSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SecurityPoliciesClient) Insert(ctx context.Context, req *computepb.InsertSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List list all the policies that have been configured for the specified project. -func (c *SecurityPoliciesClient) List(ctx context.Context, req *computepb.ListSecurityPoliciesRequest, opts ...gax.CallOption) (*computepb.SecurityPolicyList, error) { +func (c *SecurityPoliciesClient) List(ctx context.Context, req *computepb.ListSecurityPoliciesRequest, opts ...gax.CallOption) *SecurityPolicyIterator { return c.internalClient.List(ctx, req, opts...) } @@ -137,17 +140,17 @@ func (c *SecurityPoliciesClient) ListPreconfiguredExpressionSets(ctx context.Con } // Patch patches the specified policy with the data included in the request. This cannot be used to be update the rules in the policy. Please use the per rule methods like addRule, patchRule, and removeRule instead. -func (c *SecurityPoliciesClient) Patch(ctx context.Context, req *computepb.PatchSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SecurityPoliciesClient) Patch(ctx context.Context, req *computepb.PatchSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // PatchRule patches a rule at the specified priority. -func (c *SecurityPoliciesClient) PatchRule(ctx context.Context, req *computepb.PatchRuleSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SecurityPoliciesClient) PatchRule(ctx context.Context, req *computepb.PatchRuleSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.PatchRule(ctx, req, opts...) } // RemoveRule deletes a rule at the specified priority. -func (c *SecurityPoliciesClient) RemoveRule(ctx context.Context, req *computepb.RemoveRuleSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SecurityPoliciesClient) RemoveRule(ctx context.Context, req *computepb.RemoveRuleSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemoveRule(ctx, req, opts...) } @@ -216,7 +219,7 @@ func (c *securityPoliciesRESTClient) Connection() *grpc.ClientConn { } // AddRule inserts a rule into a security policy. -func (c *securityPoliciesRESTClient) AddRule(ctx context.Context, req *computepb.AddRuleSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *securityPoliciesRESTClient) AddRule(ctx context.Context, req *computepb.AddRuleSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSecurityPolicyRuleResource() jsonReq, err := m.Marshal(body) @@ -256,11 +259,15 @@ func (c *securityPoliciesRESTClient) AddRule(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Delete deletes the specified policy. -func (c *securityPoliciesRESTClient) Delete(ctx context.Context, req *computepb.DeleteSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *securityPoliciesRESTClient) Delete(ctx context.Context, req *computepb.DeleteSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/securityPolicies/%v", req.GetProject(), req.GetSecurityPolicy()) @@ -300,7 +307,11 @@ func (c *securityPoliciesRESTClient) Delete(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get list all of the ordered rules present in a single specified policy. @@ -385,7 +396,7 @@ func (c *securityPoliciesRESTClient) GetRule(ctx context.Context, req *computepb } // Insert creates a new policy in the specified project using the data included in the request. -func (c *securityPoliciesRESTClient) Insert(ctx context.Context, req *computepb.InsertSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *securityPoliciesRESTClient) Insert(ctx context.Context, req *computepb.InsertSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSecurityPolicyResource() jsonReq, err := m.Marshal(body) @@ -432,63 +443,95 @@ func (c *securityPoliciesRESTClient) Insert(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List list all the policies that have been configured for the specified project. -func (c *securityPoliciesRESTClient) List(ctx context.Context, req *computepb.ListSecurityPoliciesRequest, opts ...gax.CallOption) (*computepb.SecurityPolicyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/securityPolicies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List list all the policies that have been configured for the specified project. +func (c *securityPoliciesRESTClient) List(ctx context.Context, req *computepb.ListSecurityPoliciesRequest, opts ...gax.CallOption) *SecurityPolicyIterator { + it := &SecurityPolicyIterator{} + req = proto.Clone(req).(*computepb.ListSecurityPoliciesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.SecurityPolicyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.SecurityPolicy, string, error) { + resp := &computepb.SecurityPolicyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/securityPolicies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListPreconfiguredExpressionSets gets the current list of preconfigured Web Application Firewall (WAF) expressions. @@ -548,7 +591,7 @@ func (c *securityPoliciesRESTClient) ListPreconfiguredExpressionSets(ctx context } // Patch patches the specified policy with the data included in the request. This cannot be used to be update the rules in the policy. Please use the per rule methods like addRule, patchRule, and removeRule instead. -func (c *securityPoliciesRESTClient) Patch(ctx context.Context, req *computepb.PatchSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *securityPoliciesRESTClient) Patch(ctx context.Context, req *computepb.PatchSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSecurityPolicyResource() jsonReq, err := m.Marshal(body) @@ -595,11 +638,15 @@ func (c *securityPoliciesRESTClient) Patch(ctx context.Context, req *computepb.P unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // PatchRule patches a rule at the specified priority. -func (c *securityPoliciesRESTClient) PatchRule(ctx context.Context, req *computepb.PatchRuleSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *securityPoliciesRESTClient) PatchRule(ctx context.Context, req *computepb.PatchRuleSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSecurityPolicyRuleResource() jsonReq, err := m.Marshal(body) @@ -646,11 +693,15 @@ func (c *securityPoliciesRESTClient) PatchRule(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // RemoveRule deletes a rule at the specified priority. -func (c *securityPoliciesRESTClient) RemoveRule(ctx context.Context, req *computepb.RemoveRuleSecurityPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *securityPoliciesRESTClient) RemoveRule(ctx context.Context, req *computepb.RemoveRuleSecurityPolicyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/securityPolicies/%v/removeRule", req.GetProject(), req.GetSecurityPolicy()) @@ -690,5 +741,56 @@ func (c *securityPoliciesRESTClient) RemoveRule(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// SecurityPolicyIterator manages a stream of *computepb.SecurityPolicy. +type SecurityPolicyIterator struct { + items []*computepb.SecurityPolicy + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.SecurityPolicy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SecurityPolicyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SecurityPolicyIterator) Next() (*computepb.SecurityPolicy, error) { + var item *computepb.SecurityPolicy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SecurityPolicyIterator) bufLen() int { + return len(it.items) +} + +func (it *SecurityPolicyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/security_policies_client_example_test.go b/compute/apiv1/security_policies_client_example_test.go index 65dbeb4fc52..c7f6cb50c0e 100644 --- a/compute/apiv1/security_policies_client_example_test.go +++ b/compute/apiv1/security_policies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -141,12 +142,18 @@ func ExampleSecurityPoliciesClient_List() { req := &computepb.ListSecurityPoliciesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleSecurityPoliciesClient_ListPreconfiguredExpressionSets() { diff --git a/compute/apiv1/smoke_test.go b/compute/apiv1/smoke_test.go index ddde5a96d60..a61e1a72246 100644 --- a/compute/apiv1/smoke_test.go +++ b/compute/apiv1/smoke_test.go @@ -23,6 +23,7 @@ import ( "cloud.google.com/go/internal/testutil" "cloud.google.com/go/internal/uid" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" "google.golang.org/protobuf/proto" ) @@ -82,7 +83,7 @@ func TestCreateGetListInstance(t *testing.T) { waitZonalRequest := &computepb.WaitZoneOperationRequest{ Project: projectId, Zone: defaultZone, - Operation: insert.GetName(), + Operation: insert.Proto().GetName(), } _, err = zonesClient.Wait(ctx, waitZonalRequest) if err != nil { @@ -110,16 +111,20 @@ func TestCreateGetListInstance(t *testing.T) { Zone: defaultZone, } - list, err := c.List(ctx, listRequest) + itr := c.List(ctx, listRequest) if err != nil { t.Error(err) } - items := list.GetItems() found := false - for _, element := range items { + element, err := itr.Next() + for err == nil { if element.GetName() == name { found = true } + element, err = itr.Next() + } + if err != nil && err != iterator.Done { + t.Fatal(err) } if !found { t.Error("Couldn't find the instance in list response") @@ -198,7 +203,7 @@ func TestCreateGetRemoveSecurityPolicies(t *testing.T) { waitGlobalRequest := &computepb.WaitGlobalOperationRequest{ Project: projectId, - Operation: insert.GetName(), + Operation: insert.Proto().GetName(), } _, err = globalCLient.Wait(ctx, waitGlobalRequest) if err != nil { @@ -218,7 +223,7 @@ func TestCreateGetRemoveSecurityPolicies(t *testing.T) { } waitGlobalRequestRemove := &computepb.WaitGlobalOperationRequest{ Project: projectId, - Operation: rule.GetName(), + Operation: rule.Proto().GetName(), } _, err = globalCLient.Wait(ctx, waitGlobalRequestRemove) if err != nil { @@ -254,3 +259,139 @@ func ForceDeleteSecurityPolicy(ctx context.Context, name string, client *Securit } client.Delete(ctx, deleteRequest) } + +func TestPaginationWithMaxRes(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + c, err := NewAcceleratorTypesRESTClient(ctx) + if err != nil { + t.Fatal(err) + } + req := &computepb.ListAcceleratorTypesRequest{ + Project: projectId, + Zone: defaultZone, + MaxResults: proto.Uint32(1), + } + itr := c.List(ctx, req) + + found := false + element, err := itr.Next() + for err == nil { + if element.GetName() == "nvidia-tesla-t4" { + found = true + } + element, err = itr.Next() + } + if err != iterator.Done { + t.Fatal(err) + } + if !found { + t.Error("Couldn't find the accelerator in the response") + } +} + +func TestPaginationDefault(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + c, err := NewAcceleratorTypesRESTClient(ctx) + if err != nil { + t.Fatal(err) + } + req := &computepb.ListAcceleratorTypesRequest{ + Project: projectId, + Zone: defaultZone, + } + itr := c.List(ctx, req) + + found := false + element, err := itr.Next() + for err == nil { + if element.GetName() == "nvidia-tesla-t4" { + found = true + break + } + element, err = itr.Next() + } + if err != iterator.Done { + t.Fatal(err) + } + if !found { + t.Error("Couldn't find the accelerator in the response") + } +} + +func TestPaginationMapResponse(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + c, err := NewAcceleratorTypesRESTClient(ctx) + if err != nil { + t.Fatal(err) + } + req := &computepb.AggregatedListAcceleratorTypesRequest{ + Project: projectId, + } + itr := c.AggregatedList(ctx, req) + + found := false + element, err := itr.Next() + for err == nil { + if element.Key == "zones/us-central1-a" { + types := element.Value.GetAcceleratorTypes() + for _, item := range types { + if item.GetName() == "nvidia-tesla-t4" { + found = true + break + } + } + } + element, err = itr.Next() + } + if err != iterator.Done { + t.Fatal(err) + } + if !found { + t.Error("Couldn't find the accelerator in the response") + } +} + +func TestPaginationMapResponseMaxRes(t *testing.T) { + if testing.Short() { + t.Skip("skipping smoke test in short mode") + } + ctx := context.Background() + c, err := NewAcceleratorTypesRESTClient(ctx) + if err != nil { + t.Fatal(err) + } + req := &computepb.AggregatedListAcceleratorTypesRequest{ + Project: projectId, + MaxResults: proto.Uint32(10), + } + itr := c.AggregatedList(ctx, req) + found := false + element, err := itr.Next() + for err == nil { + if element.Key == "zones/us-central1-a" { + types := element.Value.GetAcceleratorTypes() + for _, item := range types { + if item.GetName() == "nvidia-tesla-t4" { + found = true + break + } + } + } + element, err = itr.Next() + } + if err != iterator.Done { + t.Fatal(err) + } + if !found { + t.Error("Couldn't find the accelerator in the response") + } +} diff --git a/compute/apiv1/snapshots_client.go b/compute/apiv1/snapshots_client.go index 3471e49464f..d7694cb0e7f 100644 --- a/compute/apiv1/snapshots_client.go +++ b/compute/apiv1/snapshots_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newSnapshotsClientHook clientHook @@ -52,12 +55,12 @@ type internalSnapshotsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteSnapshotRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteSnapshotRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetSnapshotRequest, ...gax.CallOption) (*computepb.Snapshot, error) GetIamPolicy(context.Context, *computepb.GetIamPolicySnapshotRequest, ...gax.CallOption) (*computepb.Policy, error) - List(context.Context, *computepb.ListSnapshotsRequest, ...gax.CallOption) (*computepb.SnapshotList, error) + List(context.Context, *computepb.ListSnapshotsRequest, ...gax.CallOption) *SnapshotIterator SetIamPolicy(context.Context, *computepb.SetIamPolicySnapshotRequest, ...gax.CallOption) (*computepb.Policy, error) - SetLabels(context.Context, *computepb.SetLabelsSnapshotRequest, ...gax.CallOption) (*computepb.Operation, error) + SetLabels(context.Context, *computepb.SetLabelsSnapshotRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsSnapshotRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -98,7 +101,7 @@ func (c *SnapshotsClient) Connection() *grpc.ClientConn { // Delete deletes the specified Snapshot resource. Keep in mind that deleting a single snapshot might not necessarily delete all the data on that snapshot. If any data on the snapshot that is marked for deletion is needed for subsequent snapshots, the data will be moved to the next corresponding snapshot. // // For more information, see Deleting snapshots. -func (c *SnapshotsClient) Delete(ctx context.Context, req *computepb.DeleteSnapshotRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SnapshotsClient) Delete(ctx context.Context, req *computepb.DeleteSnapshotRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -113,7 +116,7 @@ func (c *SnapshotsClient) GetIamPolicy(ctx context.Context, req *computepb.GetIa } // List retrieves the list of Snapshot resources contained within the specified project. -func (c *SnapshotsClient) List(ctx context.Context, req *computepb.ListSnapshotsRequest, opts ...gax.CallOption) (*computepb.SnapshotList, error) { +func (c *SnapshotsClient) List(ctx context.Context, req *computepb.ListSnapshotsRequest, opts ...gax.CallOption) *SnapshotIterator { return c.internalClient.List(ctx, req, opts...) } @@ -123,7 +126,7 @@ func (c *SnapshotsClient) SetIamPolicy(ctx context.Context, req *computepb.SetIa } // SetLabels sets the labels on a snapshot. To learn more about labels, read the Labeling Resources documentation. -func (c *SnapshotsClient) SetLabels(ctx context.Context, req *computepb.SetLabelsSnapshotRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SnapshotsClient) SetLabels(ctx context.Context, req *computepb.SetLabelsSnapshotRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetLabels(ctx, req, opts...) } @@ -199,7 +202,7 @@ func (c *snapshotsRESTClient) Connection() *grpc.ClientConn { // Delete deletes the specified Snapshot resource. Keep in mind that deleting a single snapshot might not necessarily delete all the data on that snapshot. If any data on the snapshot that is marked for deletion is needed for subsequent snapshots, the data will be moved to the next corresponding snapshot. // // For more information, see Deleting snapshots. -func (c *snapshotsRESTClient) Delete(ctx context.Context, req *computepb.DeleteSnapshotRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *snapshotsRESTClient) Delete(ctx context.Context, req *computepb.DeleteSnapshotRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/snapshots/%v", req.GetProject(), req.GetSnapshot()) @@ -239,7 +242,11 @@ func (c *snapshotsRESTClient) Delete(ctx context.Context, req *computepb.DeleteS unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified Snapshot resource. Gets a list of available snapshots by making a list() request. @@ -324,59 +331,87 @@ func (c *snapshotsRESTClient) GetIamPolicy(ctx context.Context, req *computepb.G } // List retrieves the list of Snapshot resources contained within the specified project. -func (c *snapshotsRESTClient) List(ctx context.Context, req *computepb.ListSnapshotsRequest, opts ...gax.CallOption) (*computepb.SnapshotList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/snapshots", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *snapshotsRESTClient) List(ctx context.Context, req *computepb.ListSnapshotsRequest, opts ...gax.CallOption) *SnapshotIterator { + it := &SnapshotIterator{} + req = proto.Clone(req).(*computepb.ListSnapshotsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.SnapshotList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Snapshot, string, error) { + resp := &computepb.SnapshotList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/snapshots", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -424,7 +459,7 @@ func (c *snapshotsRESTClient) SetIamPolicy(ctx context.Context, req *computepb.S } // SetLabels sets the labels on a snapshot. To learn more about labels, read the Labeling Resources documentation. -func (c *snapshotsRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsSnapshotRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *snapshotsRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsSnapshotRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetGlobalSetLabelsRequestResource() jsonReq, err := m.Marshal(body) @@ -464,7 +499,11 @@ func (c *snapshotsRESTClient) SetLabels(ctx context.Context, req *computepb.SetL unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -510,3 +549,50 @@ func (c *snapshotsRESTClient) TestIamPermissions(ctx context.Context, req *compu return rsp, unm.Unmarshal(buf, rsp) } + +// SnapshotIterator manages a stream of *computepb.Snapshot. +type SnapshotIterator struct { + items []*computepb.Snapshot + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Snapshot, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SnapshotIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SnapshotIterator) Next() (*computepb.Snapshot, error) { + var item *computepb.Snapshot + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SnapshotIterator) bufLen() int { + return len(it.items) +} + +func (it *SnapshotIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/snapshots_client_example_test.go b/compute/apiv1/snapshots_client_example_test.go index ebdb2d2c377..0cc57d680b8 100644 --- a/compute/apiv1/snapshots_client_example_test.go +++ b/compute/apiv1/snapshots_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleSnapshotsClient_List() { req := &computepb.ListSnapshotsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleSnapshotsClient_SetIamPolicy() { diff --git a/compute/apiv1/ssl_certificates_client.go b/compute/apiv1/ssl_certificates_client.go index 532984964de..4a48c80c473 100644 --- a/compute/apiv1/ssl_certificates_client.go +++ b/compute/apiv1/ssl_certificates_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newSslCertificatesClientHook clientHook @@ -50,11 +54,11 @@ type internalSslCertificatesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListSslCertificatesRequest, ...gax.CallOption) (*computepb.SslCertificateAggregatedList, error) - Delete(context.Context, *computepb.DeleteSslCertificateRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListSslCertificatesRequest, ...gax.CallOption) *SslCertificatesScopedListPairIterator + Delete(context.Context, *computepb.DeleteSslCertificateRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetSslCertificateRequest, ...gax.CallOption) (*computepb.SslCertificate, error) - Insert(context.Context, *computepb.InsertSslCertificateRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListSslCertificatesRequest, ...gax.CallOption) (*computepb.SslCertificateList, error) + Insert(context.Context, *computepb.InsertSslCertificateRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListSslCertificatesRequest, ...gax.CallOption) *SslCertificateIterator } // SslCertificatesClient is a client for interacting with Google Compute Engine API. @@ -92,12 +96,12 @@ func (c *SslCertificatesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all SslCertificate resources, regional and global, available to the specified project. -func (c *SslCertificatesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListSslCertificatesRequest, opts ...gax.CallOption) (*computepb.SslCertificateAggregatedList, error) { +func (c *SslCertificatesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListSslCertificatesRequest, opts ...gax.CallOption) *SslCertificatesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified SslCertificate resource. -func (c *SslCertificatesClient) Delete(ctx context.Context, req *computepb.DeleteSslCertificateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SslCertificatesClient) Delete(ctx context.Context, req *computepb.DeleteSslCertificateRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -107,12 +111,12 @@ func (c *SslCertificatesClient) Get(ctx context.Context, req *computepb.GetSslCe } // Insert creates a SslCertificate resource in the specified project using the data included in the request. -func (c *SslCertificatesClient) Insert(ctx context.Context, req *computepb.InsertSslCertificateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SslCertificatesClient) Insert(ctx context.Context, req *computepb.InsertSslCertificateRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of SslCertificate resources available to the specified project. -func (c *SslCertificatesClient) List(ctx context.Context, req *computepb.ListSslCertificatesRequest, opts ...gax.CallOption) (*computepb.SslCertificateList, error) { +func (c *SslCertificatesClient) List(ctx context.Context, req *computepb.ListSslCertificatesRequest, opts ...gax.CallOption) *SslCertificateIterator { return c.internalClient.List(ctx, req, opts...) } @@ -181,66 +185,101 @@ func (c *sslCertificatesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all SslCertificate resources, regional and global, available to the specified project. -func (c *sslCertificatesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListSslCertificatesRequest, opts ...gax.CallOption) (*computepb.SslCertificateAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/sslCertificates", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *sslCertificatesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListSslCertificatesRequest, opts ...gax.CallOption) *SslCertificatesScopedListPairIterator { + it := &SslCertificatesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListSslCertificatesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.SslCertificateAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]SslCertificatesScopedListPair, string, error) { + resp := &computepb.SslCertificateAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/sslCertificates", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]SslCertificatesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, SslCertificatesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified SslCertificate resource. -func (c *sslCertificatesRESTClient) Delete(ctx context.Context, req *computepb.DeleteSslCertificateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *sslCertificatesRESTClient) Delete(ctx context.Context, req *computepb.DeleteSslCertificateRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/sslCertificates/%v", req.GetProject(), req.GetSslCertificate()) @@ -280,7 +319,11 @@ func (c *sslCertificatesRESTClient) Delete(ctx context.Context, req *computepb.D unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified SslCertificate resource. Gets a list of available SSL certificates by making a list() request. @@ -321,7 +364,7 @@ func (c *sslCertificatesRESTClient) Get(ctx context.Context, req *computepb.GetS } // Insert creates a SslCertificate resource in the specified project using the data included in the request. -func (c *sslCertificatesRESTClient) Insert(ctx context.Context, req *computepb.InsertSslCertificateRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *sslCertificatesRESTClient) Insert(ctx context.Context, req *computepb.InsertSslCertificateRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSslCertificateResource() jsonReq, err := m.Marshal(body) @@ -368,61 +411,146 @@ func (c *sslCertificatesRESTClient) Insert(ctx context.Context, req *computepb.I unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List retrieves the list of SslCertificate resources available to the specified project. -func (c *sslCertificatesRESTClient) List(ctx context.Context, req *computepb.ListSslCertificatesRequest, opts ...gax.CallOption) (*computepb.SslCertificateList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/sslCertificates", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() +func (c *sslCertificatesRESTClient) List(ctx context.Context, req *computepb.ListSslCertificatesRequest, opts ...gax.CallOption) *SslCertificateIterator { + it := &SslCertificateIterator{} + req = proto.Clone(req).(*computepb.ListSslCertificatesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.SslCertificate, string, error) { + resp := &computepb.SslCertificateList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/sslCertificates", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it +} - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} +// SslCertificatesScopedListPair is a holder type for string/*computepb.SslCertificatesScopedList map entries +type SslCertificatesScopedListPair struct { + Key string + Value *computepb.SslCertificatesScopedList +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// SslCertificatesScopedListPairIterator manages a stream of SslCertificatesScopedListPair. +type SslCertificatesScopedListPairIterator struct { + items []SslCertificatesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []SslCertificatesScopedListPair, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SslCertificatesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SslCertificatesScopedListPairIterator) Next() (SslCertificatesScopedListPair, error) { + var item SslCertificatesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.SslCertificateList{} +func (it *SslCertificatesScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *SslCertificatesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/ssl_certificates_client_example_test.go b/compute/apiv1/ssl_certificates_client_example_test.go index 2859305e6cf..4cd785ea167 100644 --- a/compute/apiv1/ssl_certificates_client_example_test.go +++ b/compute/apiv1/ssl_certificates_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleSslCertificatesClient_AggregatedList() { req := &computepb.AggregatedListSslCertificatesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleSslCertificatesClient_Delete() { @@ -122,10 +129,16 @@ func ExampleSslCertificatesClient_List() { req := &computepb.ListSslCertificatesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/ssl_policies_client.go b/compute/apiv1/ssl_policies_client.go index 09ffee34b8c..b1097e7fe74 100644 --- a/compute/apiv1/ssl_policies_client.go +++ b/compute/apiv1/ssl_policies_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newSslPoliciesClientHook clientHook @@ -51,12 +54,12 @@ type internalSslPoliciesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteSslPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteSslPolicyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetSslPolicyRequest, ...gax.CallOption) (*computepb.SslPolicy, error) - Insert(context.Context, *computepb.InsertSslPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListSslPoliciesRequest, ...gax.CallOption) (*computepb.SslPoliciesList, error) + Insert(context.Context, *computepb.InsertSslPolicyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListSslPoliciesRequest, ...gax.CallOption) *SslPolicyIterator ListAvailableFeatures(context.Context, *computepb.ListAvailableFeaturesSslPoliciesRequest, ...gax.CallOption) (*computepb.SslPoliciesListAvailableFeaturesResponse, error) - Patch(context.Context, *computepb.PatchSslPolicyRequest, ...gax.CallOption) (*computepb.Operation, error) + Patch(context.Context, *computepb.PatchSslPolicyRequest, ...gax.CallOption) (*Operation, error) } // SslPoliciesClient is a client for interacting with Google Compute Engine API. @@ -94,7 +97,7 @@ func (c *SslPoliciesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified SSL policy. The SSL policy resource can be deleted only if it is not in use by any TargetHttpsProxy or TargetSslProxy resources. -func (c *SslPoliciesClient) Delete(ctx context.Context, req *computepb.DeleteSslPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SslPoliciesClient) Delete(ctx context.Context, req *computepb.DeleteSslPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -104,12 +107,12 @@ func (c *SslPoliciesClient) Get(ctx context.Context, req *computepb.GetSslPolicy } // Insert returns the specified SSL policy resource. Gets a list of available SSL policies by making a list() request. -func (c *SslPoliciesClient) Insert(ctx context.Context, req *computepb.InsertSslPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SslPoliciesClient) Insert(ctx context.Context, req *computepb.InsertSslPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List lists all the SSL policies that have been configured for the specified project. -func (c *SslPoliciesClient) List(ctx context.Context, req *computepb.ListSslPoliciesRequest, opts ...gax.CallOption) (*computepb.SslPoliciesList, error) { +func (c *SslPoliciesClient) List(ctx context.Context, req *computepb.ListSslPoliciesRequest, opts ...gax.CallOption) *SslPolicyIterator { return c.internalClient.List(ctx, req, opts...) } @@ -119,7 +122,7 @@ func (c *SslPoliciesClient) ListAvailableFeatures(ctx context.Context, req *comp } // Patch patches the specified SSL policy with the data included in the request. -func (c *SslPoliciesClient) Patch(ctx context.Context, req *computepb.PatchSslPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SslPoliciesClient) Patch(ctx context.Context, req *computepb.PatchSslPolicyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -188,7 +191,7 @@ func (c *sslPoliciesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified SSL policy. The SSL policy resource can be deleted only if it is not in use by any TargetHttpsProxy or TargetSslProxy resources. -func (c *sslPoliciesRESTClient) Delete(ctx context.Context, req *computepb.DeleteSslPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *sslPoliciesRESTClient) Delete(ctx context.Context, req *computepb.DeleteSslPolicyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/sslPolicies/%v", req.GetProject(), req.GetSslPolicy()) @@ -228,7 +231,11 @@ func (c *sslPoliciesRESTClient) Delete(ctx context.Context, req *computepb.Delet unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get lists all of the ordered rules present in a single specified policy. @@ -269,7 +276,7 @@ func (c *sslPoliciesRESTClient) Get(ctx context.Context, req *computepb.GetSslPo } // Insert returns the specified SSL policy resource. Gets a list of available SSL policies by making a list() request. -func (c *sslPoliciesRESTClient) Insert(ctx context.Context, req *computepb.InsertSslPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *sslPoliciesRESTClient) Insert(ctx context.Context, req *computepb.InsertSslPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSslPolicyResource() jsonReq, err := m.Marshal(body) @@ -316,63 +323,95 @@ func (c *sslPoliciesRESTClient) Insert(ctx context.Context, req *computepb.Inser unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List lists all the SSL policies that have been configured for the specified project. -func (c *sslPoliciesRESTClient) List(ctx context.Context, req *computepb.ListSslPoliciesRequest, opts ...gax.CallOption) (*computepb.SslPoliciesList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/sslPolicies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List lists all the SSL policies that have been configured for the specified project. +func (c *sslPoliciesRESTClient) List(ctx context.Context, req *computepb.ListSslPoliciesRequest, opts ...gax.CallOption) *SslPolicyIterator { + it := &SslPolicyIterator{} + req = proto.Clone(req).(*computepb.ListSslPoliciesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.SslPoliciesList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.SslPolicy, string, error) { + resp := &computepb.SslPoliciesList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/sslPolicies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListAvailableFeatures lists all features that can be specified in the SSL policy when using custom profile. @@ -432,7 +471,7 @@ func (c *sslPoliciesRESTClient) ListAvailableFeatures(ctx context.Context, req * } // Patch patches the specified SSL policy with the data included in the request. -func (c *sslPoliciesRESTClient) Patch(ctx context.Context, req *computepb.PatchSslPolicyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *sslPoliciesRESTClient) Patch(ctx context.Context, req *computepb.PatchSslPolicyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSslPolicyResource() jsonReq, err := m.Marshal(body) @@ -479,5 +518,56 @@ func (c *sslPoliciesRESTClient) Patch(ctx context.Context, req *computepb.PatchS unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// SslPolicyIterator manages a stream of *computepb.SslPolicy. +type SslPolicyIterator struct { + items []*computepb.SslPolicy + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.SslPolicy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SslPolicyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SslPolicyIterator) Next() (*computepb.SslPolicy, error) { + var item *computepb.SslPolicy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SslPolicyIterator) bufLen() int { + return len(it.items) +} + +func (it *SslPolicyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/ssl_policies_client_example_test.go b/compute/apiv1/ssl_policies_client_example_test.go index a74e2832e04..82ce6c7dcf4 100644 --- a/compute/apiv1/ssl_policies_client_example_test.go +++ b/compute/apiv1/ssl_policies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleSslPoliciesClient_List() { req := &computepb.ListSslPoliciesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleSslPoliciesClient_ListAvailableFeatures() { diff --git a/compute/apiv1/subnetworks_client.go b/compute/apiv1/subnetworks_client.go index d7fef62581c..8788e2f06eb 100644 --- a/compute/apiv1/subnetworks_client.go +++ b/compute/apiv1/subnetworks_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newSubnetworksClientHook clientHook @@ -57,17 +61,17 @@ type internalSubnetworksClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListSubnetworksRequest, ...gax.CallOption) (*computepb.SubnetworkAggregatedList, error) - Delete(context.Context, *computepb.DeleteSubnetworkRequest, ...gax.CallOption) (*computepb.Operation, error) - ExpandIpCidrRange(context.Context, *computepb.ExpandIpCidrRangeSubnetworkRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListSubnetworksRequest, ...gax.CallOption) *SubnetworksScopedListPairIterator + Delete(context.Context, *computepb.DeleteSubnetworkRequest, ...gax.CallOption) (*Operation, error) + ExpandIpCidrRange(context.Context, *computepb.ExpandIpCidrRangeSubnetworkRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetSubnetworkRequest, ...gax.CallOption) (*computepb.Subnetwork, error) GetIamPolicy(context.Context, *computepb.GetIamPolicySubnetworkRequest, ...gax.CallOption) (*computepb.Policy, error) - Insert(context.Context, *computepb.InsertSubnetworkRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListSubnetworksRequest, ...gax.CallOption) (*computepb.SubnetworkList, error) - ListUsable(context.Context, *computepb.ListUsableSubnetworksRequest, ...gax.CallOption) (*computepb.UsableSubnetworksAggregatedList, error) - Patch(context.Context, *computepb.PatchSubnetworkRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertSubnetworkRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListSubnetworksRequest, ...gax.CallOption) *SubnetworkIterator + ListUsable(context.Context, *computepb.ListUsableSubnetworksRequest, ...gax.CallOption) *UsableSubnetworkIterator + Patch(context.Context, *computepb.PatchSubnetworkRequest, ...gax.CallOption) (*Operation, error) SetIamPolicy(context.Context, *computepb.SetIamPolicySubnetworkRequest, ...gax.CallOption) (*computepb.Policy, error) - SetPrivateIpGoogleAccess(context.Context, *computepb.SetPrivateIpGoogleAccessSubnetworkRequest, ...gax.CallOption) (*computepb.Operation, error) + SetPrivateIpGoogleAccess(context.Context, *computepb.SetPrivateIpGoogleAccessSubnetworkRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsSubnetworkRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -106,17 +110,17 @@ func (c *SubnetworksClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of subnetworks. -func (c *SubnetworksClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListSubnetworksRequest, opts ...gax.CallOption) (*computepb.SubnetworkAggregatedList, error) { +func (c *SubnetworksClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListSubnetworksRequest, opts ...gax.CallOption) *SubnetworksScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified subnetwork. -func (c *SubnetworksClient) Delete(ctx context.Context, req *computepb.DeleteSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SubnetworksClient) Delete(ctx context.Context, req *computepb.DeleteSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } // ExpandIpCidrRange expands the IP CIDR range of the subnetwork to a specified value. -func (c *SubnetworksClient) ExpandIpCidrRange(ctx context.Context, req *computepb.ExpandIpCidrRangeSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SubnetworksClient) ExpandIpCidrRange(ctx context.Context, req *computepb.ExpandIpCidrRangeSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.ExpandIpCidrRange(ctx, req, opts...) } @@ -131,22 +135,22 @@ func (c *SubnetworksClient) GetIamPolicy(ctx context.Context, req *computepb.Get } // Insert creates a subnetwork in the specified project using the data included in the request. -func (c *SubnetworksClient) Insert(ctx context.Context, req *computepb.InsertSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SubnetworksClient) Insert(ctx context.Context, req *computepb.InsertSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of subnetworks available to the specified project. -func (c *SubnetworksClient) List(ctx context.Context, req *computepb.ListSubnetworksRequest, opts ...gax.CallOption) (*computepb.SubnetworkList, error) { +func (c *SubnetworksClient) List(ctx context.Context, req *computepb.ListSubnetworksRequest, opts ...gax.CallOption) *SubnetworkIterator { return c.internalClient.List(ctx, req, opts...) } // ListUsable retrieves an aggregated list of all usable subnetworks in the project. -func (c *SubnetworksClient) ListUsable(ctx context.Context, req *computepb.ListUsableSubnetworksRequest, opts ...gax.CallOption) (*computepb.UsableSubnetworksAggregatedList, error) { +func (c *SubnetworksClient) ListUsable(ctx context.Context, req *computepb.ListUsableSubnetworksRequest, opts ...gax.CallOption) *UsableSubnetworkIterator { return c.internalClient.ListUsable(ctx, req, opts...) } // Patch patches the specified subnetwork with the data included in the request. Only certain fields can be updated with a patch request as indicated in the field descriptions. You must specify the current fingerprint of the subnetwork resource being patched. -func (c *SubnetworksClient) Patch(ctx context.Context, req *computepb.PatchSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SubnetworksClient) Patch(ctx context.Context, req *computepb.PatchSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -156,7 +160,7 @@ func (c *SubnetworksClient) SetIamPolicy(ctx context.Context, req *computepb.Set } // SetPrivateIpGoogleAccess set whether VMs in this subnet can access Google services without assigning external IP addresses through Private Google Access. -func (c *SubnetworksClient) SetPrivateIpGoogleAccess(ctx context.Context, req *computepb.SetPrivateIpGoogleAccessSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *SubnetworksClient) SetPrivateIpGoogleAccess(ctx context.Context, req *computepb.SetPrivateIpGoogleAccessSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetPrivateIpGoogleAccess(ctx, req, opts...) } @@ -230,66 +234,101 @@ func (c *subnetworksRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of subnetworks. -func (c *subnetworksRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListSubnetworksRequest, opts ...gax.CallOption) (*computepb.SubnetworkAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/subnetworks", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *subnetworksRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListSubnetworksRequest, opts ...gax.CallOption) *SubnetworksScopedListPairIterator { + it := &SubnetworksScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListSubnetworksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.SubnetworkAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]SubnetworksScopedListPair, string, error) { + resp := &computepb.SubnetworkAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/subnetworks", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]SubnetworksScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, SubnetworksScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified subnetwork. -func (c *subnetworksRESTClient) Delete(ctx context.Context, req *computepb.DeleteSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *subnetworksRESTClient) Delete(ctx context.Context, req *computepb.DeleteSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/subnetworks/%v", req.GetProject(), req.GetRegion(), req.GetSubnetwork()) @@ -329,11 +368,15 @@ func (c *subnetworksRESTClient) Delete(ctx context.Context, req *computepb.Delet unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // ExpandIpCidrRange expands the IP CIDR range of the subnetwork to a specified value. -func (c *subnetworksRESTClient) ExpandIpCidrRange(ctx context.Context, req *computepb.ExpandIpCidrRangeSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *subnetworksRESTClient) ExpandIpCidrRange(ctx context.Context, req *computepb.ExpandIpCidrRangeSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSubnetworksExpandIpCidrRangeRequestResource() jsonReq, err := m.Marshal(body) @@ -380,7 +423,11 @@ func (c *subnetworksRESTClient) ExpandIpCidrRange(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified subnetwork. Gets a list of available subnetworks list() request. @@ -465,7 +512,7 @@ func (c *subnetworksRESTClient) GetIamPolicy(ctx context.Context, req *computepb } // Insert creates a subnetwork in the specified project using the data included in the request. -func (c *subnetworksRESTClient) Insert(ctx context.Context, req *computepb.InsertSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *subnetworksRESTClient) Insert(ctx context.Context, req *computepb.InsertSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSubnetworkResource() jsonReq, err := m.Marshal(body) @@ -512,123 +559,183 @@ func (c *subnetworksRESTClient) Insert(ctx context.Context, req *computepb.Inser unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of subnetworks available to the specified project. -func (c *subnetworksRESTClient) List(ctx context.Context, req *computepb.ListSubnetworksRequest, opts ...gax.CallOption) (*computepb.SubnetworkList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/subnetworks", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of subnetworks available to the specified project. +func (c *subnetworksRESTClient) List(ctx context.Context, req *computepb.ListSubnetworksRequest, opts ...gax.CallOption) *SubnetworkIterator { + it := &SubnetworkIterator{} + req = proto.Clone(req).(*computepb.ListSubnetworksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.SubnetworkList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Subnetwork, string, error) { + resp := &computepb.SubnetworkList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/subnetworks", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // ListUsable retrieves an aggregated list of all usable subnetworks in the project. -func (c *subnetworksRESTClient) ListUsable(ctx context.Context, req *computepb.ListUsableSubnetworksRequest, opts ...gax.CallOption) (*computepb.UsableSubnetworksAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/subnetworks/listUsable", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *subnetworksRESTClient) ListUsable(ctx context.Context, req *computepb.ListUsableSubnetworksRequest, opts ...gax.CallOption) *UsableSubnetworkIterator { + it := &UsableSubnetworkIterator{} + req = proto.Clone(req).(*computepb.ListUsableSubnetworksRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.UsableSubnetworksAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.UsableSubnetwork, string, error) { + resp := &computepb.UsableSubnetworksAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/subnetworks/listUsable", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified subnetwork with the data included in the request. Only certain fields can be updated with a patch request as indicated in the field descriptions. You must specify the current fingerprint of the subnetwork resource being patched. -func (c *subnetworksRESTClient) Patch(ctx context.Context, req *computepb.PatchSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *subnetworksRESTClient) Patch(ctx context.Context, req *computepb.PatchSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSubnetworkResource() jsonReq, err := m.Marshal(body) @@ -678,7 +785,11 @@ func (c *subnetworksRESTClient) Patch(ctx context.Context, req *computepb.PatchS unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetIamPolicy sets the access control policy on the specified resource. Replaces any existing policy. @@ -726,7 +837,7 @@ func (c *subnetworksRESTClient) SetIamPolicy(ctx context.Context, req *computepb } // SetPrivateIpGoogleAccess set whether VMs in this subnet can access Google services without assigning external IP addresses through Private Google Access. -func (c *subnetworksRESTClient) SetPrivateIpGoogleAccess(ctx context.Context, req *computepb.SetPrivateIpGoogleAccessSubnetworkRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *subnetworksRESTClient) SetPrivateIpGoogleAccess(ctx context.Context, req *computepb.SetPrivateIpGoogleAccessSubnetworkRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSubnetworksSetPrivateIpGoogleAccessRequestResource() jsonReq, err := m.Marshal(body) @@ -773,7 +884,11 @@ func (c *subnetworksRESTClient) SetPrivateIpGoogleAccess(ctx context.Context, re unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -819,3 +934,150 @@ func (c *subnetworksRESTClient) TestIamPermissions(ctx context.Context, req *com return rsp, unm.Unmarshal(buf, rsp) } + +// SubnetworkIterator manages a stream of *computepb.Subnetwork. +type SubnetworkIterator struct { + items []*computepb.Subnetwork + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Subnetwork, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SubnetworkIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SubnetworkIterator) Next() (*computepb.Subnetwork, error) { + var item *computepb.Subnetwork + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SubnetworkIterator) bufLen() int { + return len(it.items) +} + +func (it *SubnetworkIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// SubnetworksScopedListPair is a holder type for string/*computepb.SubnetworksScopedList map entries +type SubnetworksScopedListPair struct { + Key string + Value *computepb.SubnetworksScopedList +} + +// SubnetworksScopedListPairIterator manages a stream of SubnetworksScopedListPair. +type SubnetworksScopedListPairIterator struct { + items []SubnetworksScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []SubnetworksScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *SubnetworksScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *SubnetworksScopedListPairIterator) Next() (SubnetworksScopedListPair, error) { + var item SubnetworksScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *SubnetworksScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *SubnetworksScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// UsableSubnetworkIterator manages a stream of *computepb.UsableSubnetwork. +type UsableSubnetworkIterator struct { + items []*computepb.UsableSubnetwork + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.UsableSubnetwork, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *UsableSubnetworkIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *UsableSubnetworkIterator) Next() (*computepb.UsableSubnetwork, error) { + var item *computepb.UsableSubnetwork + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *UsableSubnetworkIterator) bufLen() int { + return len(it.items) +} + +func (it *UsableSubnetworkIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/subnetworks_client_example_test.go b/compute/apiv1/subnetworks_client_example_test.go index c561c8311df..e418892253b 100644 --- a/compute/apiv1/subnetworks_client_example_test.go +++ b/compute/apiv1/subnetworks_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleSubnetworksClient_AggregatedList() { req := &computepb.AggregatedListSubnetworksRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleSubnetworksClient_Delete() { @@ -160,12 +167,18 @@ func ExampleSubnetworksClient_List() { req := &computepb.ListSubnetworksRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleSubnetworksClient_ListUsable() { @@ -179,12 +192,18 @@ func ExampleSubnetworksClient_ListUsable() { req := &computepb.ListUsableSubnetworksRequest{ // TODO: Fill request struct fields. } - resp, err := c.ListUsable(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.ListUsable(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleSubnetworksClient_Patch() { diff --git a/compute/apiv1/target_grpc_proxies_client.go b/compute/apiv1/target_grpc_proxies_client.go index abd27748bc0..7dd0a9ac770 100644 --- a/compute/apiv1/target_grpc_proxies_client.go +++ b/compute/apiv1/target_grpc_proxies_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newTargetGrpcProxiesClientHook clientHook @@ -50,11 +53,11 @@ type internalTargetGrpcProxiesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteTargetGrpcProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteTargetGrpcProxyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetTargetGrpcProxyRequest, ...gax.CallOption) (*computepb.TargetGrpcProxy, error) - Insert(context.Context, *computepb.InsertTargetGrpcProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListTargetGrpcProxiesRequest, ...gax.CallOption) (*computepb.TargetGrpcProxyList, error) - Patch(context.Context, *computepb.PatchTargetGrpcProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertTargetGrpcProxyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListTargetGrpcProxiesRequest, ...gax.CallOption) *TargetGrpcProxyIterator + Patch(context.Context, *computepb.PatchTargetGrpcProxyRequest, ...gax.CallOption) (*Operation, error) } // TargetGrpcProxiesClient is a client for interacting with Google Compute Engine API. @@ -92,7 +95,7 @@ func (c *TargetGrpcProxiesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetGrpcProxy in the given scope -func (c *TargetGrpcProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetGrpcProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetGrpcProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetGrpcProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -102,17 +105,17 @@ func (c *TargetGrpcProxiesClient) Get(ctx context.Context, req *computepb.GetTar } // Insert creates a TargetGrpcProxy in the specified project in the given scope using the parameters that are included in the request. -func (c *TargetGrpcProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetGrpcProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetGrpcProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetGrpcProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List lists the TargetGrpcProxies for a project in the given scope. -func (c *TargetGrpcProxiesClient) List(ctx context.Context, req *computepb.ListTargetGrpcProxiesRequest, opts ...gax.CallOption) (*computepb.TargetGrpcProxyList, error) { +func (c *TargetGrpcProxiesClient) List(ctx context.Context, req *computepb.ListTargetGrpcProxiesRequest, opts ...gax.CallOption) *TargetGrpcProxyIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified TargetGrpcProxy resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *TargetGrpcProxiesClient) Patch(ctx context.Context, req *computepb.PatchTargetGrpcProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetGrpcProxiesClient) Patch(ctx context.Context, req *computepb.PatchTargetGrpcProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } @@ -181,7 +184,7 @@ func (c *targetGrpcProxiesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetGrpcProxy in the given scope -func (c *targetGrpcProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetGrpcProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetGrpcProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetGrpcProxyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetGrpcProxies/%v", req.GetProject(), req.GetTargetGrpcProxy()) @@ -221,7 +224,11 @@ func (c *targetGrpcProxiesRESTClient) Delete(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified TargetGrpcProxy resource in the given scope. @@ -262,7 +269,7 @@ func (c *targetGrpcProxiesRESTClient) Get(ctx context.Context, req *computepb.Ge } // Insert creates a TargetGrpcProxy in the specified project in the given scope using the parameters that are included in the request. -func (c *targetGrpcProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetGrpcProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetGrpcProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetGrpcProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetGrpcProxyResource() jsonReq, err := m.Marshal(body) @@ -309,67 +316,99 @@ func (c *targetGrpcProxiesRESTClient) Insert(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List lists the TargetGrpcProxies for a project in the given scope. -func (c *targetGrpcProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetGrpcProxiesRequest, opts ...gax.CallOption) (*computepb.TargetGrpcProxyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetGrpcProxies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List lists the TargetGrpcProxies for a project in the given scope. +func (c *targetGrpcProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetGrpcProxiesRequest, opts ...gax.CallOption) *TargetGrpcProxyIterator { + it := &TargetGrpcProxyIterator{} + req = proto.Clone(req).(*computepb.ListTargetGrpcProxiesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetGrpcProxyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetGrpcProxy, string, error) { + resp := &computepb.TargetGrpcProxyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetGrpcProxies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified TargetGrpcProxy resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. -func (c *targetGrpcProxiesRESTClient) Patch(ctx context.Context, req *computepb.PatchTargetGrpcProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetGrpcProxiesRESTClient) Patch(ctx context.Context, req *computepb.PatchTargetGrpcProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetGrpcProxyResource() jsonReq, err := m.Marshal(body) @@ -416,5 +455,56 @@ func (c *targetGrpcProxiesRESTClient) Patch(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// TargetGrpcProxyIterator manages a stream of *computepb.TargetGrpcProxy. +type TargetGrpcProxyIterator struct { + items []*computepb.TargetGrpcProxy + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.TargetGrpcProxy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetGrpcProxyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetGrpcProxyIterator) Next() (*computepb.TargetGrpcProxy, error) { + var item *computepb.TargetGrpcProxy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TargetGrpcProxyIterator) bufLen() int { + return len(it.items) +} + +func (it *TargetGrpcProxyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/target_grpc_proxies_client_example_test.go b/compute/apiv1/target_grpc_proxies_client_example_test.go index b1fdef19971..aa90300ee2d 100644 --- a/compute/apiv1/target_grpc_proxies_client_example_test.go +++ b/compute/apiv1/target_grpc_proxies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleTargetGrpcProxiesClient_List() { req := &computepb.ListTargetGrpcProxiesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetGrpcProxiesClient_Patch() { diff --git a/compute/apiv1/target_http_proxies_client.go b/compute/apiv1/target_http_proxies_client.go index 785e4550dec..c4458deb258 100644 --- a/compute/apiv1/target_http_proxies_client.go +++ b/compute/apiv1/target_http_proxies_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newTargetHttpProxiesClientHook clientHook @@ -52,13 +56,13 @@ type internalTargetHttpProxiesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListTargetHttpProxiesRequest, ...gax.CallOption) (*computepb.TargetHttpProxyAggregatedList, error) - Delete(context.Context, *computepb.DeleteTargetHttpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListTargetHttpProxiesRequest, ...gax.CallOption) *TargetHttpProxiesScopedListPairIterator + Delete(context.Context, *computepb.DeleteTargetHttpProxyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetTargetHttpProxyRequest, ...gax.CallOption) (*computepb.TargetHttpProxy, error) - Insert(context.Context, *computepb.InsertTargetHttpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListTargetHttpProxiesRequest, ...gax.CallOption) (*computepb.TargetHttpProxyList, error) - Patch(context.Context, *computepb.PatchTargetHttpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetUrlMap(context.Context, *computepb.SetUrlMapTargetHttpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertTargetHttpProxyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListTargetHttpProxiesRequest, ...gax.CallOption) *TargetHttpProxyIterator + Patch(context.Context, *computepb.PatchTargetHttpProxyRequest, ...gax.CallOption) (*Operation, error) + SetUrlMap(context.Context, *computepb.SetUrlMapTargetHttpProxyRequest, ...gax.CallOption) (*Operation, error) } // TargetHttpProxiesClient is a client for interacting with Google Compute Engine API. @@ -96,12 +100,12 @@ func (c *TargetHttpProxiesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all TargetHttpProxy resources, regional and global, available to the specified project. -func (c *TargetHttpProxiesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetHttpProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpProxyAggregatedList, error) { +func (c *TargetHttpProxiesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetHttpProxiesRequest, opts ...gax.CallOption) *TargetHttpProxiesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified TargetHttpProxy resource. -func (c *TargetHttpProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -111,22 +115,22 @@ func (c *TargetHttpProxiesClient) Get(ctx context.Context, req *computepb.GetTar } // Insert creates a TargetHttpProxy resource in the specified project using the data included in the request. -func (c *TargetHttpProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of TargetHttpProxy resources available to the specified project. -func (c *TargetHttpProxiesClient) List(ctx context.Context, req *computepb.ListTargetHttpProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpProxyList, error) { +func (c *TargetHttpProxiesClient) List(ctx context.Context, req *computepb.ListTargetHttpProxiesRequest, opts ...gax.CallOption) *TargetHttpProxyIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified TargetHttpProxy resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. (== suppress_warning http-rest-shadowed ==) -func (c *TargetHttpProxiesClient) Patch(ctx context.Context, req *computepb.PatchTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpProxiesClient) Patch(ctx context.Context, req *computepb.PatchTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // SetUrlMap changes the URL map for TargetHttpProxy. -func (c *TargetHttpProxiesClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpProxiesClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetUrlMap(ctx, req, opts...) } @@ -195,66 +199,101 @@ func (c *targetHttpProxiesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all TargetHttpProxy resources, regional and global, available to the specified project. -func (c *targetHttpProxiesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetHttpProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpProxyAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetHttpProxies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *targetHttpProxiesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetHttpProxiesRequest, opts ...gax.CallOption) *TargetHttpProxiesScopedListPairIterator { + it := &TargetHttpProxiesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListTargetHttpProxiesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetHttpProxyAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]TargetHttpProxiesScopedListPair, string, error) { + resp := &computepb.TargetHttpProxyAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetHttpProxies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]TargetHttpProxiesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, TargetHttpProxiesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified TargetHttpProxy resource. -func (c *targetHttpProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetHttpProxies/%v", req.GetProject(), req.GetTargetHttpProxy()) @@ -294,7 +333,11 @@ func (c *targetHttpProxiesRESTClient) Delete(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified TargetHttpProxy resource. Gets a list of available target HTTP proxies by making a list() request. @@ -335,7 +378,7 @@ func (c *targetHttpProxiesRESTClient) Get(ctx context.Context, req *computepb.Ge } // Insert creates a TargetHttpProxy resource in the specified project using the data included in the request. -func (c *targetHttpProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetHttpProxyResource() jsonReq, err := m.Marshal(body) @@ -382,67 +425,99 @@ func (c *targetHttpProxiesRESTClient) Insert(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of TargetHttpProxy resources available to the specified project. -func (c *targetHttpProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetHttpProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpProxyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetHttpProxies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of TargetHttpProxy resources available to the specified project. +func (c *targetHttpProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetHttpProxiesRequest, opts ...gax.CallOption) *TargetHttpProxyIterator { + it := &TargetHttpProxyIterator{} + req = proto.Clone(req).(*computepb.ListTargetHttpProxiesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetHttpProxyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetHttpProxy, string, error) { + resp := &computepb.TargetHttpProxyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetHttpProxies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified TargetHttpProxy resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. (== suppress_warning http-rest-shadowed ==) -func (c *targetHttpProxiesRESTClient) Patch(ctx context.Context, req *computepb.PatchTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpProxiesRESTClient) Patch(ctx context.Context, req *computepb.PatchTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetHttpProxyResource() jsonReq, err := m.Marshal(body) @@ -489,11 +564,15 @@ func (c *targetHttpProxiesRESTClient) Patch(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetUrlMap changes the URL map for TargetHttpProxy. -func (c *targetHttpProxiesRESTClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapTargetHttpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpProxiesRESTClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapTargetHttpProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapReferenceResource() jsonReq, err := m.Marshal(body) @@ -540,5 +619,62 @@ func (c *targetHttpProxiesRESTClient) SetUrlMap(ctx context.Context, req *comput unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// TargetHttpProxiesScopedListPair is a holder type for string/*computepb.TargetHttpProxiesScopedList map entries +type TargetHttpProxiesScopedListPair struct { + Key string + Value *computepb.TargetHttpProxiesScopedList +} + +// TargetHttpProxiesScopedListPairIterator manages a stream of TargetHttpProxiesScopedListPair. +type TargetHttpProxiesScopedListPairIterator struct { + items []TargetHttpProxiesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []TargetHttpProxiesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetHttpProxiesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetHttpProxiesScopedListPairIterator) Next() (TargetHttpProxiesScopedListPair, error) { + var item TargetHttpProxiesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TargetHttpProxiesScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *TargetHttpProxiesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/target_http_proxies_client_example_test.go b/compute/apiv1/target_http_proxies_client_example_test.go index 07d31ff9562..f736574ed24 100644 --- a/compute/apiv1/target_http_proxies_client_example_test.go +++ b/compute/apiv1/target_http_proxies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleTargetHttpProxiesClient_AggregatedList() { req := &computepb.AggregatedListTargetHttpProxiesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetHttpProxiesClient_Delete() { @@ -122,12 +129,18 @@ func ExampleTargetHttpProxiesClient_List() { req := &computepb.ListTargetHttpProxiesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetHttpProxiesClient_Patch() { diff --git a/compute/apiv1/target_https_proxies_client.go b/compute/apiv1/target_https_proxies_client.go index d1f47cabb4d..c0f739c2f4f 100644 --- a/compute/apiv1/target_https_proxies_client.go +++ b/compute/apiv1/target_https_proxies_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newTargetHttpsProxiesClientHook clientHook @@ -55,16 +59,16 @@ type internalTargetHttpsProxiesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListTargetHttpsProxiesRequest, ...gax.CallOption) (*computepb.TargetHttpsProxyAggregatedList, error) - Delete(context.Context, *computepb.DeleteTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListTargetHttpsProxiesRequest, ...gax.CallOption) *TargetHttpsProxiesScopedListPairIterator + Delete(context.Context, *computepb.DeleteTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.TargetHttpsProxy, error) - Insert(context.Context, *computepb.InsertTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListTargetHttpsProxiesRequest, ...gax.CallOption) (*computepb.TargetHttpsProxyList, error) - Patch(context.Context, *computepb.PatchTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetQuicOverride(context.Context, *computepb.SetQuicOverrideTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetSslCertificates(context.Context, *computepb.SetSslCertificatesTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetSslPolicy(context.Context, *computepb.SetSslPolicyTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetUrlMap(context.Context, *computepb.SetUrlMapTargetHttpsProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListTargetHttpsProxiesRequest, ...gax.CallOption) *TargetHttpsProxyIterator + Patch(context.Context, *computepb.PatchTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) + SetQuicOverride(context.Context, *computepb.SetQuicOverrideTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) + SetSslCertificates(context.Context, *computepb.SetSslCertificatesTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) + SetSslPolicy(context.Context, *computepb.SetSslPolicyTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) + SetUrlMap(context.Context, *computepb.SetUrlMapTargetHttpsProxyRequest, ...gax.CallOption) (*Operation, error) } // TargetHttpsProxiesClient is a client for interacting with Google Compute Engine API. @@ -102,12 +106,12 @@ func (c *TargetHttpsProxiesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all TargetHttpsProxy resources, regional and global, available to the specified project. -func (c *TargetHttpsProxiesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetHttpsProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpsProxyAggregatedList, error) { +func (c *TargetHttpsProxiesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetHttpsProxiesRequest, opts ...gax.CallOption) *TargetHttpsProxiesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified TargetHttpsProxy resource. -func (c *TargetHttpsProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpsProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -117,37 +121,37 @@ func (c *TargetHttpsProxiesClient) Get(ctx context.Context, req *computepb.GetTa } // Insert creates a TargetHttpsProxy resource in the specified project using the data included in the request. -func (c *TargetHttpsProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpsProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of TargetHttpsProxy resources available to the specified project. -func (c *TargetHttpsProxiesClient) List(ctx context.Context, req *computepb.ListTargetHttpsProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpsProxyList, error) { +func (c *TargetHttpsProxiesClient) List(ctx context.Context, req *computepb.ListTargetHttpsProxiesRequest, opts ...gax.CallOption) *TargetHttpsProxyIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified TargetHttpsProxy resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. (== suppress_warning http-rest-shadowed ==) -func (c *TargetHttpsProxiesClient) Patch(ctx context.Context, req *computepb.PatchTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpsProxiesClient) Patch(ctx context.Context, req *computepb.PatchTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // SetQuicOverride sets the QUIC override policy for TargetHttpsProxy. -func (c *TargetHttpsProxiesClient) SetQuicOverride(ctx context.Context, req *computepb.SetQuicOverrideTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpsProxiesClient) SetQuicOverride(ctx context.Context, req *computepb.SetQuicOverrideTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetQuicOverride(ctx, req, opts...) } // SetSslCertificates replaces SslCertificates for TargetHttpsProxy. -func (c *TargetHttpsProxiesClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpsProxiesClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetSslCertificates(ctx, req, opts...) } // SetSslPolicy sets the SSL policy for TargetHttpsProxy. The SSL policy specifies the server-side support for SSL features. This affects connections between clients and the HTTPS proxy load balancer. They do not affect the connection between the load balancer and the backends. -func (c *TargetHttpsProxiesClient) SetSslPolicy(ctx context.Context, req *computepb.SetSslPolicyTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpsProxiesClient) SetSslPolicy(ctx context.Context, req *computepb.SetSslPolicyTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetSslPolicy(ctx, req, opts...) } // SetUrlMap changes the URL map for TargetHttpsProxy. -func (c *TargetHttpsProxiesClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetHttpsProxiesClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetUrlMap(ctx, req, opts...) } @@ -216,66 +220,101 @@ func (c *targetHttpsProxiesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all TargetHttpsProxy resources, regional and global, available to the specified project. -func (c *targetHttpsProxiesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetHttpsProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpsProxyAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetHttpsProxies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *targetHttpsProxiesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetHttpsProxiesRequest, opts ...gax.CallOption) *TargetHttpsProxiesScopedListPairIterator { + it := &TargetHttpsProxiesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListTargetHttpsProxiesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetHttpsProxyAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]TargetHttpsProxiesScopedListPair, string, error) { + resp := &computepb.TargetHttpsProxyAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetHttpsProxies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]TargetHttpsProxiesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, TargetHttpsProxiesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified TargetHttpsProxy resource. -func (c *targetHttpsProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpsProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetHttpsProxies/%v", req.GetProject(), req.GetTargetHttpsProxy()) @@ -315,7 +354,11 @@ func (c *targetHttpsProxiesRESTClient) Delete(ctx context.Context, req *computep unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified TargetHttpsProxy resource. Gets a list of available target HTTPS proxies by making a list() request. @@ -356,7 +399,7 @@ func (c *targetHttpsProxiesRESTClient) Get(ctx context.Context, req *computepb.G } // Insert creates a TargetHttpsProxy resource in the specified project using the data included in the request. -func (c *targetHttpsProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpsProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetHttpsProxyResource() jsonReq, err := m.Marshal(body) @@ -403,67 +446,99 @@ func (c *targetHttpsProxiesRESTClient) Insert(ctx context.Context, req *computep unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of TargetHttpsProxy resources available to the specified project. -func (c *targetHttpsProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetHttpsProxiesRequest, opts ...gax.CallOption) (*computepb.TargetHttpsProxyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetHttpsProxies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of TargetHttpsProxy resources available to the specified project. +func (c *targetHttpsProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetHttpsProxiesRequest, opts ...gax.CallOption) *TargetHttpsProxyIterator { + it := &TargetHttpsProxyIterator{} + req = proto.Clone(req).(*computepb.ListTargetHttpsProxiesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetHttpsProxyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetHttpsProxy, string, error) { + resp := &computepb.TargetHttpsProxyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetHttpsProxies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified TargetHttpsProxy resource with the data included in the request. This method supports PATCH semantics and uses JSON merge patch format and processing rules. (== suppress_warning http-rest-shadowed ==) -func (c *targetHttpsProxiesRESTClient) Patch(ctx context.Context, req *computepb.PatchTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpsProxiesRESTClient) Patch(ctx context.Context, req *computepb.PatchTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetHttpsProxyResource() jsonReq, err := m.Marshal(body) @@ -510,11 +585,15 @@ func (c *targetHttpsProxiesRESTClient) Patch(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetQuicOverride sets the QUIC override policy for TargetHttpsProxy. -func (c *targetHttpsProxiesRESTClient) SetQuicOverride(ctx context.Context, req *computepb.SetQuicOverrideTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpsProxiesRESTClient) SetQuicOverride(ctx context.Context, req *computepb.SetQuicOverrideTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetHttpsProxiesSetQuicOverrideRequestResource() jsonReq, err := m.Marshal(body) @@ -561,11 +640,15 @@ func (c *targetHttpsProxiesRESTClient) SetQuicOverride(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetSslCertificates replaces SslCertificates for TargetHttpsProxy. -func (c *targetHttpsProxiesRESTClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpsProxiesRESTClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetHttpsProxiesSetSslCertificatesRequestResource() jsonReq, err := m.Marshal(body) @@ -612,11 +695,15 @@ func (c *targetHttpsProxiesRESTClient) SetSslCertificates(ctx context.Context, r unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetSslPolicy sets the SSL policy for TargetHttpsProxy. The SSL policy specifies the server-side support for SSL features. This affects connections between clients and the HTTPS proxy load balancer. They do not affect the connection between the load balancer and the backends. -func (c *targetHttpsProxiesRESTClient) SetSslPolicy(ctx context.Context, req *computepb.SetSslPolicyTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpsProxiesRESTClient) SetSslPolicy(ctx context.Context, req *computepb.SetSslPolicyTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSslPolicyReferenceResource() jsonReq, err := m.Marshal(body) @@ -663,11 +750,15 @@ func (c *targetHttpsProxiesRESTClient) SetSslPolicy(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetUrlMap changes the URL map for TargetHttpsProxy. -func (c *targetHttpsProxiesRESTClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapTargetHttpsProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetHttpsProxiesRESTClient) SetUrlMap(ctx context.Context, req *computepb.SetUrlMapTargetHttpsProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapReferenceResource() jsonReq, err := m.Marshal(body) @@ -714,5 +805,62 @@ func (c *targetHttpsProxiesRESTClient) SetUrlMap(ctx context.Context, req *compu unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// TargetHttpsProxiesScopedListPair is a holder type for string/*computepb.TargetHttpsProxiesScopedList map entries +type TargetHttpsProxiesScopedListPair struct { + Key string + Value *computepb.TargetHttpsProxiesScopedList +} + +// TargetHttpsProxiesScopedListPairIterator manages a stream of TargetHttpsProxiesScopedListPair. +type TargetHttpsProxiesScopedListPairIterator struct { + items []TargetHttpsProxiesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []TargetHttpsProxiesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetHttpsProxiesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetHttpsProxiesScopedListPairIterator) Next() (TargetHttpsProxiesScopedListPair, error) { + var item TargetHttpsProxiesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TargetHttpsProxiesScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *TargetHttpsProxiesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/target_https_proxies_client_example_test.go b/compute/apiv1/target_https_proxies_client_example_test.go index 3430ce2206f..c1c6185a447 100644 --- a/compute/apiv1/target_https_proxies_client_example_test.go +++ b/compute/apiv1/target_https_proxies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleTargetHttpsProxiesClient_AggregatedList() { req := &computepb.AggregatedListTargetHttpsProxiesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetHttpsProxiesClient_Delete() { @@ -122,12 +129,18 @@ func ExampleTargetHttpsProxiesClient_List() { req := &computepb.ListTargetHttpsProxiesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetHttpsProxiesClient_Patch() { diff --git a/compute/apiv1/target_instances_client.go b/compute/apiv1/target_instances_client.go index 49d4ddd9ffd..9659a6b3070 100644 --- a/compute/apiv1/target_instances_client.go +++ b/compute/apiv1/target_instances_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newTargetInstancesClientHook clientHook @@ -50,11 +54,11 @@ type internalTargetInstancesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListTargetInstancesRequest, ...gax.CallOption) (*computepb.TargetInstanceAggregatedList, error) - Delete(context.Context, *computepb.DeleteTargetInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListTargetInstancesRequest, ...gax.CallOption) *TargetInstancesScopedListPairIterator + Delete(context.Context, *computepb.DeleteTargetInstanceRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetTargetInstanceRequest, ...gax.CallOption) (*computepb.TargetInstance, error) - Insert(context.Context, *computepb.InsertTargetInstanceRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListTargetInstancesRequest, ...gax.CallOption) (*computepb.TargetInstanceList, error) + Insert(context.Context, *computepb.InsertTargetInstanceRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListTargetInstancesRequest, ...gax.CallOption) *TargetInstanceIterator } // TargetInstancesClient is a client for interacting with Google Compute Engine API. @@ -92,12 +96,12 @@ func (c *TargetInstancesClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of target instances. -func (c *TargetInstancesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetInstancesRequest, opts ...gax.CallOption) (*computepb.TargetInstanceAggregatedList, error) { +func (c *TargetInstancesClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetInstancesRequest, opts ...gax.CallOption) *TargetInstancesScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified TargetInstance resource. -func (c *TargetInstancesClient) Delete(ctx context.Context, req *computepb.DeleteTargetInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetInstancesClient) Delete(ctx context.Context, req *computepb.DeleteTargetInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -107,12 +111,12 @@ func (c *TargetInstancesClient) Get(ctx context.Context, req *computepb.GetTarge } // Insert creates a TargetInstance resource in the specified project and zone using the data included in the request. -func (c *TargetInstancesClient) Insert(ctx context.Context, req *computepb.InsertTargetInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetInstancesClient) Insert(ctx context.Context, req *computepb.InsertTargetInstanceRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of TargetInstance resources available to the specified project and zone. -func (c *TargetInstancesClient) List(ctx context.Context, req *computepb.ListTargetInstancesRequest, opts ...gax.CallOption) (*computepb.TargetInstanceList, error) { +func (c *TargetInstancesClient) List(ctx context.Context, req *computepb.ListTargetInstancesRequest, opts ...gax.CallOption) *TargetInstanceIterator { return c.internalClient.List(ctx, req, opts...) } @@ -181,66 +185,101 @@ func (c *targetInstancesRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of target instances. -func (c *targetInstancesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetInstancesRequest, opts ...gax.CallOption) (*computepb.TargetInstanceAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetInstances", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *targetInstancesRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetInstancesRequest, opts ...gax.CallOption) *TargetInstancesScopedListPairIterator { + it := &TargetInstancesScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListTargetInstancesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetInstanceAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]TargetInstancesScopedListPair, string, error) { + resp := &computepb.TargetInstanceAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetInstances", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]TargetInstancesScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, TargetInstancesScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified TargetInstance resource. -func (c *targetInstancesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetInstancesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetInstanceRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/targetInstances/%v", req.GetProject(), req.GetZone(), req.GetTargetInstance()) @@ -280,7 +319,11 @@ func (c *targetInstancesRESTClient) Delete(ctx context.Context, req *computepb.D unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified TargetInstance resource. Gets a list of available target instances by making a list() request. @@ -321,7 +364,7 @@ func (c *targetInstancesRESTClient) Get(ctx context.Context, req *computepb.GetT } // Insert creates a TargetInstance resource in the specified project and zone using the data included in the request. -func (c *targetInstancesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetInstanceRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetInstancesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetInstanceRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetInstanceResource() jsonReq, err := m.Marshal(body) @@ -368,61 +411,193 @@ func (c *targetInstancesRESTClient) Insert(ctx context.Context, req *computepb.I unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List retrieves a list of TargetInstance resources available to the specified project and zone. -func (c *targetInstancesRESTClient) List(ctx context.Context, req *computepb.ListTargetInstancesRequest, opts ...gax.CallOption) (*computepb.TargetInstanceList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/targetInstances", req.GetProject(), req.GetZone()) +func (c *targetInstancesRESTClient) List(ctx context.Context, req *computepb.ListTargetInstancesRequest, opts ...gax.CallOption) *TargetInstanceIterator { + it := &TargetInstanceIterator{} + req = proto.Clone(req).(*computepb.ListTargetInstancesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetInstance, string, error) { + resp := &computepb.TargetInstanceList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/targetInstances", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it +} - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } +// TargetInstanceIterator manages a stream of *computepb.TargetInstance. +type TargetInstanceIterator struct { + items []*computepb.TargetInstance + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.TargetInstance, nextPageToken string, err error) +} - baseUrl.RawQuery = params.Encode() +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetInstanceIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetInstanceIterator) Next() (*computepb.TargetInstance, error) { + var item *computepb.TargetInstance + if err := it.nextFunc(); err != nil { + return item, err } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +func (it *TargetInstanceIterator) bufLen() int { + return len(it.items) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +func (it *TargetInstanceIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// TargetInstancesScopedListPair is a holder type for string/*computepb.TargetInstancesScopedList map entries +type TargetInstancesScopedListPair struct { + Key string + Value *computepb.TargetInstancesScopedList +} + +// TargetInstancesScopedListPairIterator manages a stream of TargetInstancesScopedListPair. +type TargetInstancesScopedListPairIterator struct { + items []TargetInstancesScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []TargetInstancesScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetInstancesScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetInstancesScopedListPairIterator) Next() (TargetInstancesScopedListPair, error) { + var item TargetInstancesScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetInstanceList{} +func (it *TargetInstancesScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *TargetInstancesScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/target_instances_client_example_test.go b/compute/apiv1/target_instances_client_example_test.go index de3679b3076..e60c67736f0 100644 --- a/compute/apiv1/target_instances_client_example_test.go +++ b/compute/apiv1/target_instances_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleTargetInstancesClient_AggregatedList() { req := &computepb.AggregatedListTargetInstancesRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetInstancesClient_Delete() { @@ -122,10 +129,16 @@ func ExampleTargetInstancesClient_List() { req := &computepb.ListTargetInstancesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/target_pools_client.go b/compute/apiv1/target_pools_client.go index 5f311bfb383..14510b61127 100644 --- a/compute/apiv1/target_pools_client.go +++ b/compute/apiv1/target_pools_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newTargetPoolsClientHook clientHook @@ -56,17 +60,17 @@ type internalTargetPoolsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AddHealthCheck(context.Context, *computepb.AddHealthCheckTargetPoolRequest, ...gax.CallOption) (*computepb.Operation, error) - AddInstance(context.Context, *computepb.AddInstanceTargetPoolRequest, ...gax.CallOption) (*computepb.Operation, error) - AggregatedList(context.Context, *computepb.AggregatedListTargetPoolsRequest, ...gax.CallOption) (*computepb.TargetPoolAggregatedList, error) - Delete(context.Context, *computepb.DeleteTargetPoolRequest, ...gax.CallOption) (*computepb.Operation, error) + AddHealthCheck(context.Context, *computepb.AddHealthCheckTargetPoolRequest, ...gax.CallOption) (*Operation, error) + AddInstance(context.Context, *computepb.AddInstanceTargetPoolRequest, ...gax.CallOption) (*Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListTargetPoolsRequest, ...gax.CallOption) *TargetPoolsScopedListPairIterator + Delete(context.Context, *computepb.DeleteTargetPoolRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetTargetPoolRequest, ...gax.CallOption) (*computepb.TargetPool, error) GetHealth(context.Context, *computepb.GetHealthTargetPoolRequest, ...gax.CallOption) (*computepb.TargetPoolInstanceHealth, error) - Insert(context.Context, *computepb.InsertTargetPoolRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListTargetPoolsRequest, ...gax.CallOption) (*computepb.TargetPoolList, error) - RemoveHealthCheck(context.Context, *computepb.RemoveHealthCheckTargetPoolRequest, ...gax.CallOption) (*computepb.Operation, error) - RemoveInstance(context.Context, *computepb.RemoveInstanceTargetPoolRequest, ...gax.CallOption) (*computepb.Operation, error) - SetBackup(context.Context, *computepb.SetBackupTargetPoolRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertTargetPoolRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListTargetPoolsRequest, ...gax.CallOption) *TargetPoolIterator + RemoveHealthCheck(context.Context, *computepb.RemoveHealthCheckTargetPoolRequest, ...gax.CallOption) (*Operation, error) + RemoveInstance(context.Context, *computepb.RemoveInstanceTargetPoolRequest, ...gax.CallOption) (*Operation, error) + SetBackup(context.Context, *computepb.SetBackupTargetPoolRequest, ...gax.CallOption) (*Operation, error) } // TargetPoolsClient is a client for interacting with Google Compute Engine API. @@ -104,22 +108,22 @@ func (c *TargetPoolsClient) Connection() *grpc.ClientConn { } // AddHealthCheck adds health check URLs to a target pool. -func (c *TargetPoolsClient) AddHealthCheck(ctx context.Context, req *computepb.AddHealthCheckTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetPoolsClient) AddHealthCheck(ctx context.Context, req *computepb.AddHealthCheckTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddHealthCheck(ctx, req, opts...) } // AddInstance adds an instance to a target pool. -func (c *TargetPoolsClient) AddInstance(ctx context.Context, req *computepb.AddInstanceTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetPoolsClient) AddInstance(ctx context.Context, req *computepb.AddInstanceTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.AddInstance(ctx, req, opts...) } // AggregatedList retrieves an aggregated list of target pools. -func (c *TargetPoolsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetPoolsRequest, opts ...gax.CallOption) (*computepb.TargetPoolAggregatedList, error) { +func (c *TargetPoolsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetPoolsRequest, opts ...gax.CallOption) *TargetPoolsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified target pool. -func (c *TargetPoolsClient) Delete(ctx context.Context, req *computepb.DeleteTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetPoolsClient) Delete(ctx context.Context, req *computepb.DeleteTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -134,27 +138,27 @@ func (c *TargetPoolsClient) GetHealth(ctx context.Context, req *computepb.GetHea } // Insert creates a target pool in the specified project and region using the data included in the request. -func (c *TargetPoolsClient) Insert(ctx context.Context, req *computepb.InsertTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetPoolsClient) Insert(ctx context.Context, req *computepb.InsertTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of target pools available to the specified project and region. -func (c *TargetPoolsClient) List(ctx context.Context, req *computepb.ListTargetPoolsRequest, opts ...gax.CallOption) (*computepb.TargetPoolList, error) { +func (c *TargetPoolsClient) List(ctx context.Context, req *computepb.ListTargetPoolsRequest, opts ...gax.CallOption) *TargetPoolIterator { return c.internalClient.List(ctx, req, opts...) } // RemoveHealthCheck removes health check URL from a target pool. -func (c *TargetPoolsClient) RemoveHealthCheck(ctx context.Context, req *computepb.RemoveHealthCheckTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetPoolsClient) RemoveHealthCheck(ctx context.Context, req *computepb.RemoveHealthCheckTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemoveHealthCheck(ctx, req, opts...) } // RemoveInstance removes instance URL from a target pool. -func (c *TargetPoolsClient) RemoveInstance(ctx context.Context, req *computepb.RemoveInstanceTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetPoolsClient) RemoveInstance(ctx context.Context, req *computepb.RemoveInstanceTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.RemoveInstance(ctx, req, opts...) } // SetBackup changes a backup target pool’s configurations. -func (c *TargetPoolsClient) SetBackup(ctx context.Context, req *computepb.SetBackupTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetPoolsClient) SetBackup(ctx context.Context, req *computepb.SetBackupTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetBackup(ctx, req, opts...) } @@ -223,7 +227,7 @@ func (c *targetPoolsRESTClient) Connection() *grpc.ClientConn { } // AddHealthCheck adds health check URLs to a target pool. -func (c *targetPoolsRESTClient) AddHealthCheck(ctx context.Context, req *computepb.AddHealthCheckTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetPoolsRESTClient) AddHealthCheck(ctx context.Context, req *computepb.AddHealthCheckTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetPoolsAddHealthCheckRequestResource() jsonReq, err := m.Marshal(body) @@ -270,11 +274,15 @@ func (c *targetPoolsRESTClient) AddHealthCheck(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // AddInstance adds an instance to a target pool. -func (c *targetPoolsRESTClient) AddInstance(ctx context.Context, req *computepb.AddInstanceTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetPoolsRESTClient) AddInstance(ctx context.Context, req *computepb.AddInstanceTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetPoolsAddInstanceRequestResource() jsonReq, err := m.Marshal(body) @@ -321,70 +329,109 @@ func (c *targetPoolsRESTClient) AddInstance(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// AggregatedList retrieves an aggregated list of target pools. -func (c *targetPoolsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetPoolsRequest, opts ...gax.CallOption) (*computepb.TargetPoolAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetPools", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// AggregatedList retrieves an aggregated list of target pools. +func (c *targetPoolsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetPoolsRequest, opts ...gax.CallOption) *TargetPoolsScopedListPairIterator { + it := &TargetPoolsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListTargetPoolsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetPoolAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]TargetPoolsScopedListPair, string, error) { + resp := &computepb.TargetPoolAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetPools", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]TargetPoolsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, TargetPoolsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified target pool. -func (c *targetPoolsRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetPoolsRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetPools/%v", req.GetProject(), req.GetRegion(), req.GetTargetPool()) @@ -424,7 +471,11 @@ func (c *targetPoolsRESTClient) Delete(ctx context.Context, req *computepb.Delet unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified target pool. Gets a list of available target pools by making a list() request. @@ -509,7 +560,7 @@ func (c *targetPoolsRESTClient) GetHealth(ctx context.Context, req *computepb.Ge } // Insert creates a target pool in the specified project and region using the data included in the request. -func (c *targetPoolsRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetPoolsRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetPoolResource() jsonReq, err := m.Marshal(body) @@ -556,67 +607,99 @@ func (c *targetPoolsRESTClient) Insert(ctx context.Context, req *computepb.Inser unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of target pools available to the specified project and region. -func (c *targetPoolsRESTClient) List(ctx context.Context, req *computepb.ListTargetPoolsRequest, opts ...gax.CallOption) (*computepb.TargetPoolList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetPools", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of target pools available to the specified project and region. +func (c *targetPoolsRESTClient) List(ctx context.Context, req *computepb.ListTargetPoolsRequest, opts ...gax.CallOption) *TargetPoolIterator { + it := &TargetPoolIterator{} + req = proto.Clone(req).(*computepb.ListTargetPoolsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetPoolList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetPool, string, error) { + resp := &computepb.TargetPoolList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetPools", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // RemoveHealthCheck removes health check URL from a target pool. -func (c *targetPoolsRESTClient) RemoveHealthCheck(ctx context.Context, req *computepb.RemoveHealthCheckTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetPoolsRESTClient) RemoveHealthCheck(ctx context.Context, req *computepb.RemoveHealthCheckTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetPoolsRemoveHealthCheckRequestResource() jsonReq, err := m.Marshal(body) @@ -663,11 +746,15 @@ func (c *targetPoolsRESTClient) RemoveHealthCheck(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // RemoveInstance removes instance URL from a target pool. -func (c *targetPoolsRESTClient) RemoveInstance(ctx context.Context, req *computepb.RemoveInstanceTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetPoolsRESTClient) RemoveInstance(ctx context.Context, req *computepb.RemoveInstanceTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetPoolsRemoveInstanceRequestResource() jsonReq, err := m.Marshal(body) @@ -714,11 +801,15 @@ func (c *targetPoolsRESTClient) RemoveInstance(ctx context.Context, req *compute unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetBackup changes a backup target pool’s configurations. -func (c *targetPoolsRESTClient) SetBackup(ctx context.Context, req *computepb.SetBackupTargetPoolRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetPoolsRESTClient) SetBackup(ctx context.Context, req *computepb.SetBackupTargetPoolRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetReferenceResource() jsonReq, err := m.Marshal(body) @@ -768,5 +859,109 @@ func (c *targetPoolsRESTClient) SetBackup(ctx context.Context, req *computepb.Se unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// TargetPoolIterator manages a stream of *computepb.TargetPool. +type TargetPoolIterator struct { + items []*computepb.TargetPool + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.TargetPool, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetPoolIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetPoolIterator) Next() (*computepb.TargetPool, error) { + var item *computepb.TargetPool + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TargetPoolIterator) bufLen() int { + return len(it.items) +} + +func (it *TargetPoolIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// TargetPoolsScopedListPair is a holder type for string/*computepb.TargetPoolsScopedList map entries +type TargetPoolsScopedListPair struct { + Key string + Value *computepb.TargetPoolsScopedList +} + +// TargetPoolsScopedListPairIterator manages a stream of TargetPoolsScopedListPair. +type TargetPoolsScopedListPairIterator struct { + items []TargetPoolsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []TargetPoolsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetPoolsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetPoolsScopedListPairIterator) Next() (TargetPoolsScopedListPair, error) { + var item TargetPoolsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TargetPoolsScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *TargetPoolsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/target_pools_client_example_test.go b/compute/apiv1/target_pools_client_example_test.go index 480016f09eb..138e6f6da5e 100644 --- a/compute/apiv1/target_pools_client_example_test.go +++ b/compute/apiv1/target_pools_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -84,12 +85,18 @@ func ExampleTargetPoolsClient_AggregatedList() { req := &computepb.AggregatedListTargetPoolsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetPoolsClient_Delete() { @@ -179,12 +186,18 @@ func ExampleTargetPoolsClient_List() { req := &computepb.ListTargetPoolsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetPoolsClient_RemoveHealthCheck() { diff --git a/compute/apiv1/target_ssl_proxies_client.go b/compute/apiv1/target_ssl_proxies_client.go index a8cb73198ca..449328b2242 100644 --- a/compute/apiv1/target_ssl_proxies_client.go +++ b/compute/apiv1/target_ssl_proxies_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newTargetSslProxiesClientHook clientHook @@ -53,14 +56,14 @@ type internalTargetSslProxiesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteTargetSslProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteTargetSslProxyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetTargetSslProxyRequest, ...gax.CallOption) (*computepb.TargetSslProxy, error) - Insert(context.Context, *computepb.InsertTargetSslProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListTargetSslProxiesRequest, ...gax.CallOption) (*computepb.TargetSslProxyList, error) - SetBackendService(context.Context, *computepb.SetBackendServiceTargetSslProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetProxyHeader(context.Context, *computepb.SetProxyHeaderTargetSslProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetSslCertificates(context.Context, *computepb.SetSslCertificatesTargetSslProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetSslPolicy(context.Context, *computepb.SetSslPolicyTargetSslProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertTargetSslProxyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListTargetSslProxiesRequest, ...gax.CallOption) *TargetSslProxyIterator + SetBackendService(context.Context, *computepb.SetBackendServiceTargetSslProxyRequest, ...gax.CallOption) (*Operation, error) + SetProxyHeader(context.Context, *computepb.SetProxyHeaderTargetSslProxyRequest, ...gax.CallOption) (*Operation, error) + SetSslCertificates(context.Context, *computepb.SetSslCertificatesTargetSslProxyRequest, ...gax.CallOption) (*Operation, error) + SetSslPolicy(context.Context, *computepb.SetSslPolicyTargetSslProxyRequest, ...gax.CallOption) (*Operation, error) } // TargetSslProxiesClient is a client for interacting with Google Compute Engine API. @@ -98,7 +101,7 @@ func (c *TargetSslProxiesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetSslProxy resource. -func (c *TargetSslProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetSslProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -108,32 +111,32 @@ func (c *TargetSslProxiesClient) Get(ctx context.Context, req *computepb.GetTarg } // Insert creates a TargetSslProxy resource in the specified project using the data included in the request. -func (c *TargetSslProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetSslProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of TargetSslProxy resources available to the specified project. -func (c *TargetSslProxiesClient) List(ctx context.Context, req *computepb.ListTargetSslProxiesRequest, opts ...gax.CallOption) (*computepb.TargetSslProxyList, error) { +func (c *TargetSslProxiesClient) List(ctx context.Context, req *computepb.ListTargetSslProxiesRequest, opts ...gax.CallOption) *TargetSslProxyIterator { return c.internalClient.List(ctx, req, opts...) } // SetBackendService changes the BackendService for TargetSslProxy. -func (c *TargetSslProxiesClient) SetBackendService(ctx context.Context, req *computepb.SetBackendServiceTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetSslProxiesClient) SetBackendService(ctx context.Context, req *computepb.SetBackendServiceTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetBackendService(ctx, req, opts...) } // SetProxyHeader changes the ProxyHeaderType for TargetSslProxy. -func (c *TargetSslProxiesClient) SetProxyHeader(ctx context.Context, req *computepb.SetProxyHeaderTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetSslProxiesClient) SetProxyHeader(ctx context.Context, req *computepb.SetProxyHeaderTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetProxyHeader(ctx, req, opts...) } // SetSslCertificates changes SslCertificates for TargetSslProxy. -func (c *TargetSslProxiesClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetSslProxiesClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetSslCertificates(ctx, req, opts...) } // SetSslPolicy sets the SSL policy for TargetSslProxy. The SSL policy specifies the server-side support for SSL features. This affects connections between clients and the SSL proxy load balancer. They do not affect the connection between the load balancer and the backends. -func (c *TargetSslProxiesClient) SetSslPolicy(ctx context.Context, req *computepb.SetSslPolicyTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetSslProxiesClient) SetSslPolicy(ctx context.Context, req *computepb.SetSslPolicyTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetSslPolicy(ctx, req, opts...) } @@ -202,7 +205,7 @@ func (c *targetSslProxiesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetSslProxy resource. -func (c *targetSslProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetSslProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetSslProxies/%v", req.GetProject(), req.GetTargetSslProxy()) @@ -242,7 +245,11 @@ func (c *targetSslProxiesRESTClient) Delete(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified TargetSslProxy resource. Gets a list of available target SSL proxies by making a list() request. @@ -283,7 +290,7 @@ func (c *targetSslProxiesRESTClient) Get(ctx context.Context, req *computepb.Get } // Insert creates a TargetSslProxy resource in the specified project using the data included in the request. -func (c *targetSslProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetSslProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetSslProxyResource() jsonReq, err := m.Marshal(body) @@ -330,67 +337,99 @@ func (c *targetSslProxiesRESTClient) Insert(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of TargetSslProxy resources available to the specified project. -func (c *targetSslProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetSslProxiesRequest, opts ...gax.CallOption) (*computepb.TargetSslProxyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetSslProxies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of TargetSslProxy resources available to the specified project. +func (c *targetSslProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetSslProxiesRequest, opts ...gax.CallOption) *TargetSslProxyIterator { + it := &TargetSslProxyIterator{} + req = proto.Clone(req).(*computepb.ListTargetSslProxiesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetSslProxyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetSslProxy, string, error) { + resp := &computepb.TargetSslProxyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetSslProxies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetBackendService changes the BackendService for TargetSslProxy. -func (c *targetSslProxiesRESTClient) SetBackendService(ctx context.Context, req *computepb.SetBackendServiceTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetSslProxiesRESTClient) SetBackendService(ctx context.Context, req *computepb.SetBackendServiceTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetSslProxiesSetBackendServiceRequestResource() jsonReq, err := m.Marshal(body) @@ -437,11 +476,15 @@ func (c *targetSslProxiesRESTClient) SetBackendService(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetProxyHeader changes the ProxyHeaderType for TargetSslProxy. -func (c *targetSslProxiesRESTClient) SetProxyHeader(ctx context.Context, req *computepb.SetProxyHeaderTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetSslProxiesRESTClient) SetProxyHeader(ctx context.Context, req *computepb.SetProxyHeaderTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetSslProxiesSetProxyHeaderRequestResource() jsonReq, err := m.Marshal(body) @@ -488,11 +531,15 @@ func (c *targetSslProxiesRESTClient) SetProxyHeader(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetSslCertificates changes SslCertificates for TargetSslProxy. -func (c *targetSslProxiesRESTClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetSslProxiesRESTClient) SetSslCertificates(ctx context.Context, req *computepb.SetSslCertificatesTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetSslProxiesSetSslCertificatesRequestResource() jsonReq, err := m.Marshal(body) @@ -539,11 +586,15 @@ func (c *targetSslProxiesRESTClient) SetSslCertificates(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetSslPolicy sets the SSL policy for TargetSslProxy. The SSL policy specifies the server-side support for SSL features. This affects connections between clients and the SSL proxy load balancer. They do not affect the connection between the load balancer and the backends. -func (c *targetSslProxiesRESTClient) SetSslPolicy(ctx context.Context, req *computepb.SetSslPolicyTargetSslProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetSslProxiesRESTClient) SetSslPolicy(ctx context.Context, req *computepb.SetSslPolicyTargetSslProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetSslPolicyReferenceResource() jsonReq, err := m.Marshal(body) @@ -590,5 +641,56 @@ func (c *targetSslProxiesRESTClient) SetSslPolicy(ctx context.Context, req *comp unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// TargetSslProxyIterator manages a stream of *computepb.TargetSslProxy. +type TargetSslProxyIterator struct { + items []*computepb.TargetSslProxy + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.TargetSslProxy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetSslProxyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetSslProxyIterator) Next() (*computepb.TargetSslProxy, error) { + var item *computepb.TargetSslProxy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TargetSslProxyIterator) bufLen() int { + return len(it.items) +} + +func (it *TargetSslProxyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/target_ssl_proxies_client_example_test.go b/compute/apiv1/target_ssl_proxies_client_example_test.go index 09db740716c..d329d2c6741 100644 --- a/compute/apiv1/target_ssl_proxies_client_example_test.go +++ b/compute/apiv1/target_ssl_proxies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleTargetSslProxiesClient_List() { req := &computepb.ListTargetSslProxiesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetSslProxiesClient_SetBackendService() { diff --git a/compute/apiv1/target_tcp_proxies_client.go b/compute/apiv1/target_tcp_proxies_client.go index e86e197c3fe..c511b90f6b4 100644 --- a/compute/apiv1/target_tcp_proxies_client.go +++ b/compute/apiv1/target_tcp_proxies_client.go @@ -21,10 +21,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +34,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newTargetTcpProxiesClientHook clientHook @@ -51,12 +54,12 @@ type internalTargetTcpProxiesClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - Delete(context.Context, *computepb.DeleteTargetTcpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Delete(context.Context, *computepb.DeleteTargetTcpProxyRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetTargetTcpProxyRequest, ...gax.CallOption) (*computepb.TargetTcpProxy, error) - Insert(context.Context, *computepb.InsertTargetTcpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListTargetTcpProxiesRequest, ...gax.CallOption) (*computepb.TargetTcpProxyList, error) - SetBackendService(context.Context, *computepb.SetBackendServiceTargetTcpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) - SetProxyHeader(context.Context, *computepb.SetProxyHeaderTargetTcpProxyRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertTargetTcpProxyRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListTargetTcpProxiesRequest, ...gax.CallOption) *TargetTcpProxyIterator + SetBackendService(context.Context, *computepb.SetBackendServiceTargetTcpProxyRequest, ...gax.CallOption) (*Operation, error) + SetProxyHeader(context.Context, *computepb.SetProxyHeaderTargetTcpProxyRequest, ...gax.CallOption) (*Operation, error) } // TargetTcpProxiesClient is a client for interacting with Google Compute Engine API. @@ -94,7 +97,7 @@ func (c *TargetTcpProxiesClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetTcpProxy resource. -func (c *TargetTcpProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetTcpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetTcpProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetTcpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -104,22 +107,22 @@ func (c *TargetTcpProxiesClient) Get(ctx context.Context, req *computepb.GetTarg } // Insert creates a TargetTcpProxy resource in the specified project using the data included in the request. -func (c *TargetTcpProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetTcpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetTcpProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetTcpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves the list of TargetTcpProxy resources available to the specified project. -func (c *TargetTcpProxiesClient) List(ctx context.Context, req *computepb.ListTargetTcpProxiesRequest, opts ...gax.CallOption) (*computepb.TargetTcpProxyList, error) { +func (c *TargetTcpProxiesClient) List(ctx context.Context, req *computepb.ListTargetTcpProxiesRequest, opts ...gax.CallOption) *TargetTcpProxyIterator { return c.internalClient.List(ctx, req, opts...) } // SetBackendService changes the BackendService for TargetTcpProxy. -func (c *TargetTcpProxiesClient) SetBackendService(ctx context.Context, req *computepb.SetBackendServiceTargetTcpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetTcpProxiesClient) SetBackendService(ctx context.Context, req *computepb.SetBackendServiceTargetTcpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetBackendService(ctx, req, opts...) } // SetProxyHeader changes the ProxyHeaderType for TargetTcpProxy. -func (c *TargetTcpProxiesClient) SetProxyHeader(ctx context.Context, req *computepb.SetProxyHeaderTargetTcpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetTcpProxiesClient) SetProxyHeader(ctx context.Context, req *computepb.SetProxyHeaderTargetTcpProxyRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetProxyHeader(ctx, req, opts...) } @@ -188,7 +191,7 @@ func (c *targetTcpProxiesRESTClient) Connection() *grpc.ClientConn { } // Delete deletes the specified TargetTcpProxy resource. -func (c *targetTcpProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetTcpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetTcpProxiesRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetTcpProxyRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetTcpProxies/%v", req.GetProject(), req.GetTargetTcpProxy()) @@ -228,7 +231,11 @@ func (c *targetTcpProxiesRESTClient) Delete(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified TargetTcpProxy resource. Gets a list of available target TCP proxies by making a list() request. @@ -269,7 +276,7 @@ func (c *targetTcpProxiesRESTClient) Get(ctx context.Context, req *computepb.Get } // Insert creates a TargetTcpProxy resource in the specified project using the data included in the request. -func (c *targetTcpProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetTcpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetTcpProxiesRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetTcpProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetTcpProxyResource() jsonReq, err := m.Marshal(body) @@ -316,67 +323,99 @@ func (c *targetTcpProxiesRESTClient) Insert(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of TargetTcpProxy resources available to the specified project. -func (c *targetTcpProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetTcpProxiesRequest, opts ...gax.CallOption) (*computepb.TargetTcpProxyList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetTcpProxies", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of TargetTcpProxy resources available to the specified project. +func (c *targetTcpProxiesRESTClient) List(ctx context.Context, req *computepb.ListTargetTcpProxiesRequest, opts ...gax.CallOption) *TargetTcpProxyIterator { + it := &TargetTcpProxyIterator{} + req = proto.Clone(req).(*computepb.ListTargetTcpProxiesRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetTcpProxyList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetTcpProxy, string, error) { + resp := &computepb.TargetTcpProxyList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/targetTcpProxies", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetBackendService changes the BackendService for TargetTcpProxy. -func (c *targetTcpProxiesRESTClient) SetBackendService(ctx context.Context, req *computepb.SetBackendServiceTargetTcpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetTcpProxiesRESTClient) SetBackendService(ctx context.Context, req *computepb.SetBackendServiceTargetTcpProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetTcpProxiesSetBackendServiceRequestResource() jsonReq, err := m.Marshal(body) @@ -423,11 +462,15 @@ func (c *targetTcpProxiesRESTClient) SetBackendService(ctx context.Context, req unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // SetProxyHeader changes the ProxyHeaderType for TargetTcpProxy. -func (c *targetTcpProxiesRESTClient) SetProxyHeader(ctx context.Context, req *computepb.SetProxyHeaderTargetTcpProxyRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetTcpProxiesRESTClient) SetProxyHeader(ctx context.Context, req *computepb.SetProxyHeaderTargetTcpProxyRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetTcpProxiesSetProxyHeaderRequestResource() jsonReq, err := m.Marshal(body) @@ -474,5 +517,56 @@ func (c *targetTcpProxiesRESTClient) SetProxyHeader(ctx context.Context, req *co unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err +} + +// TargetTcpProxyIterator manages a stream of *computepb.TargetTcpProxy. +type TargetTcpProxyIterator struct { + items []*computepb.TargetTcpProxy + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.TargetTcpProxy, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetTcpProxyIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetTcpProxyIterator) Next() (*computepb.TargetTcpProxy, error) { + var item *computepb.TargetTcpProxy + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *TargetTcpProxyIterator) bufLen() int { + return len(it.items) +} + +func (it *TargetTcpProxyIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/target_tcp_proxies_client_example_test.go b/compute/apiv1/target_tcp_proxies_client_example_test.go index 0e95e1f74eb..3f0f9116213 100644 --- a/compute/apiv1/target_tcp_proxies_client_example_test.go +++ b/compute/apiv1/target_tcp_proxies_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -103,12 +104,18 @@ func ExampleTargetTcpProxiesClient_List() { req := &computepb.ListTargetTcpProxiesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetTcpProxiesClient_SetBackendService() { diff --git a/compute/apiv1/target_vpn_gateways_client.go b/compute/apiv1/target_vpn_gateways_client.go index 2e7c138b3d5..6e5f39ce2eb 100644 --- a/compute/apiv1/target_vpn_gateways_client.go +++ b/compute/apiv1/target_vpn_gateways_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newTargetVpnGatewaysClientHook clientHook @@ -50,11 +54,11 @@ type internalTargetVpnGatewaysClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListTargetVpnGatewaysRequest, ...gax.CallOption) (*computepb.TargetVpnGatewayAggregatedList, error) - Delete(context.Context, *computepb.DeleteTargetVpnGatewayRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListTargetVpnGatewaysRequest, ...gax.CallOption) *TargetVpnGatewaysScopedListPairIterator + Delete(context.Context, *computepb.DeleteTargetVpnGatewayRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetTargetVpnGatewayRequest, ...gax.CallOption) (*computepb.TargetVpnGateway, error) - Insert(context.Context, *computepb.InsertTargetVpnGatewayRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListTargetVpnGatewaysRequest, ...gax.CallOption) (*computepb.TargetVpnGatewayList, error) + Insert(context.Context, *computepb.InsertTargetVpnGatewayRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListTargetVpnGatewaysRequest, ...gax.CallOption) *TargetVpnGatewayIterator } // TargetVpnGatewaysClient is a client for interacting with Google Compute Engine API. @@ -92,12 +96,12 @@ func (c *TargetVpnGatewaysClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of target VPN gateways. -func (c *TargetVpnGatewaysClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.TargetVpnGatewayAggregatedList, error) { +func (c *TargetVpnGatewaysClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetVpnGatewaysRequest, opts ...gax.CallOption) *TargetVpnGatewaysScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified target VPN gateway. -func (c *TargetVpnGatewaysClient) Delete(ctx context.Context, req *computepb.DeleteTargetVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetVpnGatewaysClient) Delete(ctx context.Context, req *computepb.DeleteTargetVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -107,12 +111,12 @@ func (c *TargetVpnGatewaysClient) Get(ctx context.Context, req *computepb.GetTar } // Insert creates a target VPN gateway in the specified project and region using the data included in the request. -func (c *TargetVpnGatewaysClient) Insert(ctx context.Context, req *computepb.InsertTargetVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *TargetVpnGatewaysClient) Insert(ctx context.Context, req *computepb.InsertTargetVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of target VPN gateways available to the specified project and region. -func (c *TargetVpnGatewaysClient) List(ctx context.Context, req *computepb.ListTargetVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.TargetVpnGatewayList, error) { +func (c *TargetVpnGatewaysClient) List(ctx context.Context, req *computepb.ListTargetVpnGatewaysRequest, opts ...gax.CallOption) *TargetVpnGatewayIterator { return c.internalClient.List(ctx, req, opts...) } @@ -181,66 +185,101 @@ func (c *targetVpnGatewaysRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of target VPN gateways. -func (c *targetVpnGatewaysRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.TargetVpnGatewayAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetVpnGateways", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *targetVpnGatewaysRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListTargetVpnGatewaysRequest, opts ...gax.CallOption) *TargetVpnGatewaysScopedListPairIterator { + it := &TargetVpnGatewaysScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListTargetVpnGatewaysRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetVpnGatewayAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]TargetVpnGatewaysScopedListPair, string, error) { + resp := &computepb.TargetVpnGatewayAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/targetVpnGateways", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]TargetVpnGatewaysScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, TargetVpnGatewaysScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified target VPN gateway. -func (c *targetVpnGatewaysRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetVpnGatewaysRESTClient) Delete(ctx context.Context, req *computepb.DeleteTargetVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetVpnGateways/%v", req.GetProject(), req.GetRegion(), req.GetTargetVpnGateway()) @@ -280,7 +319,11 @@ func (c *targetVpnGatewaysRESTClient) Delete(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified target VPN gateway. Gets a list of available target VPN gateways by making a list() request. @@ -321,7 +364,7 @@ func (c *targetVpnGatewaysRESTClient) Get(ctx context.Context, req *computepb.Ge } // Insert creates a target VPN gateway in the specified project and region using the data included in the request. -func (c *targetVpnGatewaysRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *targetVpnGatewaysRESTClient) Insert(ctx context.Context, req *computepb.InsertTargetVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetTargetVpnGatewayResource() jsonReq, err := m.Marshal(body) @@ -368,61 +411,193 @@ func (c *targetVpnGatewaysRESTClient) Insert(ctx context.Context, req *computepb unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List retrieves a list of target VPN gateways available to the specified project and region. -func (c *targetVpnGatewaysRESTClient) List(ctx context.Context, req *computepb.ListTargetVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.TargetVpnGatewayList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetVpnGateways", req.GetProject(), req.GetRegion()) +func (c *targetVpnGatewaysRESTClient) List(ctx context.Context, req *computepb.ListTargetVpnGatewaysRequest, opts ...gax.CallOption) *TargetVpnGatewayIterator { + it := &TargetVpnGatewayIterator{} + req = proto.Clone(req).(*computepb.ListTargetVpnGatewaysRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.TargetVpnGateway, string, error) { + resp := &computepb.TargetVpnGatewayList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/targetVpnGateways", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it +} - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } +// TargetVpnGatewayIterator manages a stream of *computepb.TargetVpnGateway. +type TargetVpnGatewayIterator struct { + items []*computepb.TargetVpnGateway + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.TargetVpnGateway, nextPageToken string, err error) +} - baseUrl.RawQuery = params.Encode() +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetVpnGatewayIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetVpnGatewayIterator) Next() (*computepb.TargetVpnGateway, error) { + var item *computepb.TargetVpnGateway + if err := it.nextFunc(); err != nil { + return item, err } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +func (it *TargetVpnGatewayIterator) bufLen() int { + return len(it.items) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +func (it *TargetVpnGatewayIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// TargetVpnGatewaysScopedListPair is a holder type for string/*computepb.TargetVpnGatewaysScopedList map entries +type TargetVpnGatewaysScopedListPair struct { + Key string + Value *computepb.TargetVpnGatewaysScopedList +} + +// TargetVpnGatewaysScopedListPairIterator manages a stream of TargetVpnGatewaysScopedListPair. +type TargetVpnGatewaysScopedListPairIterator struct { + items []TargetVpnGatewaysScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []TargetVpnGatewaysScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *TargetVpnGatewaysScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *TargetVpnGatewaysScopedListPairIterator) Next() (TargetVpnGatewaysScopedListPair, error) { + var item TargetVpnGatewaysScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.TargetVpnGatewayList{} +func (it *TargetVpnGatewaysScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *TargetVpnGatewaysScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/target_vpn_gateways_client_example_test.go b/compute/apiv1/target_vpn_gateways_client_example_test.go index 1c8e35cd606..c594c125286 100644 --- a/compute/apiv1/target_vpn_gateways_client_example_test.go +++ b/compute/apiv1/target_vpn_gateways_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleTargetVpnGatewaysClient_AggregatedList() { req := &computepb.AggregatedListTargetVpnGatewaysRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleTargetVpnGatewaysClient_Delete() { @@ -122,10 +129,16 @@ func ExampleTargetVpnGatewaysClient_List() { req := &computepb.ListTargetVpnGatewaysRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/url_maps_client.go b/compute/apiv1/url_maps_client.go index ae3740f7acf..e869244514c 100644 --- a/compute/apiv1/url_maps_client.go +++ b/compute/apiv1/url_maps_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newUrlMapsClientHook clientHook @@ -54,14 +58,14 @@ type internalUrlMapsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListUrlMapsRequest, ...gax.CallOption) (*computepb.UrlMapsAggregatedList, error) - Delete(context.Context, *computepb.DeleteUrlMapRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListUrlMapsRequest, ...gax.CallOption) *UrlMapsScopedListPairIterator + Delete(context.Context, *computepb.DeleteUrlMapRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetUrlMapRequest, ...gax.CallOption) (*computepb.UrlMap, error) - Insert(context.Context, *computepb.InsertUrlMapRequest, ...gax.CallOption) (*computepb.Operation, error) - InvalidateCache(context.Context, *computepb.InvalidateCacheUrlMapRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListUrlMapsRequest, ...gax.CallOption) (*computepb.UrlMapList, error) - Patch(context.Context, *computepb.PatchUrlMapRequest, ...gax.CallOption) (*computepb.Operation, error) - Update(context.Context, *computepb.UpdateUrlMapRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertUrlMapRequest, ...gax.CallOption) (*Operation, error) + InvalidateCache(context.Context, *computepb.InvalidateCacheUrlMapRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListUrlMapsRequest, ...gax.CallOption) *UrlMapIterator + Patch(context.Context, *computepb.PatchUrlMapRequest, ...gax.CallOption) (*Operation, error) + Update(context.Context, *computepb.UpdateUrlMapRequest, ...gax.CallOption) (*Operation, error) Validate(context.Context, *computepb.ValidateUrlMapRequest, ...gax.CallOption) (*computepb.UrlMapsValidateResponse, error) } @@ -100,12 +104,12 @@ func (c *UrlMapsClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all UrlMap resources, regional and global, available to the specified project. -func (c *UrlMapsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListUrlMapsRequest, opts ...gax.CallOption) (*computepb.UrlMapsAggregatedList, error) { +func (c *UrlMapsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListUrlMapsRequest, opts ...gax.CallOption) *UrlMapsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified UrlMap resource. -func (c *UrlMapsClient) Delete(ctx context.Context, req *computepb.DeleteUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *UrlMapsClient) Delete(ctx context.Context, req *computepb.DeleteUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -115,29 +119,29 @@ func (c *UrlMapsClient) Get(ctx context.Context, req *computepb.GetUrlMapRequest } // Insert creates a UrlMap resource in the specified project using the data included in the request. -func (c *UrlMapsClient) Insert(ctx context.Context, req *computepb.InsertUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *UrlMapsClient) Insert(ctx context.Context, req *computepb.InsertUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // InvalidateCache initiates a cache invalidation operation, invalidating the specified path, scoped to the specified UrlMap. // // For more information, see Invalidating cached content (at /cdn/docs/invalidating-cached-content). -func (c *UrlMapsClient) InvalidateCache(ctx context.Context, req *computepb.InvalidateCacheUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *UrlMapsClient) InvalidateCache(ctx context.Context, req *computepb.InvalidateCacheUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.InvalidateCache(ctx, req, opts...) } // List retrieves the list of UrlMap resources available to the specified project. -func (c *UrlMapsClient) List(ctx context.Context, req *computepb.ListUrlMapsRequest, opts ...gax.CallOption) (*computepb.UrlMapList, error) { +func (c *UrlMapsClient) List(ctx context.Context, req *computepb.ListUrlMapsRequest, opts ...gax.CallOption) *UrlMapIterator { return c.internalClient.List(ctx, req, opts...) } // Patch patches the specified UrlMap resource with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *UrlMapsClient) Patch(ctx context.Context, req *computepb.PatchUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *UrlMapsClient) Patch(ctx context.Context, req *computepb.PatchUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Patch(ctx, req, opts...) } // Update updates the specified UrlMap resource with the data included in the request. -func (c *UrlMapsClient) Update(ctx context.Context, req *computepb.UpdateUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *UrlMapsClient) Update(ctx context.Context, req *computepb.UpdateUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Update(ctx, req, opts...) } @@ -211,66 +215,101 @@ func (c *urlMapsRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves the list of all UrlMap resources, regional and global, available to the specified project. -func (c *urlMapsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListUrlMapsRequest, opts ...gax.CallOption) (*computepb.UrlMapsAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/urlMaps", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *urlMapsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListUrlMapsRequest, opts ...gax.CallOption) *UrlMapsScopedListPairIterator { + it := &UrlMapsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListUrlMapsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.UrlMapsAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]UrlMapsScopedListPair, string, error) { + resp := &computepb.UrlMapsAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/urlMaps", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]UrlMapsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, UrlMapsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified UrlMap resource. -func (c *urlMapsRESTClient) Delete(ctx context.Context, req *computepb.DeleteUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *urlMapsRESTClient) Delete(ctx context.Context, req *computepb.DeleteUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/urlMaps/%v", req.GetProject(), req.GetUrlMap()) @@ -310,7 +349,11 @@ func (c *urlMapsRESTClient) Delete(ctx context.Context, req *computepb.DeleteUrl unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified UrlMap resource. Gets a list of available URL maps by making a list() request. @@ -351,7 +394,7 @@ func (c *urlMapsRESTClient) Get(ctx context.Context, req *computepb.GetUrlMapReq } // Insert creates a UrlMap resource in the specified project using the data included in the request. -func (c *urlMapsRESTClient) Insert(ctx context.Context, req *computepb.InsertUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *urlMapsRESTClient) Insert(ctx context.Context, req *computepb.InsertUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapResource() jsonReq, err := m.Marshal(body) @@ -398,13 +441,17 @@ func (c *urlMapsRESTClient) Insert(ctx context.Context, req *computepb.InsertUrl unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // InvalidateCache initiates a cache invalidation operation, invalidating the specified path, scoped to the specified UrlMap. // // For more information, see Invalidating cached content (at /cdn/docs/invalidating-cached-content). -func (c *urlMapsRESTClient) InvalidateCache(ctx context.Context, req *computepb.InvalidateCacheUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *urlMapsRESTClient) InvalidateCache(ctx context.Context, req *computepb.InvalidateCacheUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetCacheInvalidationRuleResource() jsonReq, err := m.Marshal(body) @@ -451,67 +498,99 @@ func (c *urlMapsRESTClient) InvalidateCache(ctx context.Context, req *computepb. unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves the list of UrlMap resources available to the specified project. -func (c *urlMapsRESTClient) List(ctx context.Context, req *computepb.ListUrlMapsRequest, opts ...gax.CallOption) (*computepb.UrlMapList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/urlMaps", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves the list of UrlMap resources available to the specified project. +func (c *urlMapsRESTClient) List(ctx context.Context, req *computepb.ListUrlMapsRequest, opts ...gax.CallOption) *UrlMapIterator { + it := &UrlMapIterator{} + req = proto.Clone(req).(*computepb.ListUrlMapsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.UrlMapList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.UrlMap, string, error) { + resp := &computepb.UrlMapList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/global/urlMaps", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Patch patches the specified UrlMap resource with the data included in the request. This method supports PATCH semantics and uses the JSON merge patch format and processing rules. -func (c *urlMapsRESTClient) Patch(ctx context.Context, req *computepb.PatchUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *urlMapsRESTClient) Patch(ctx context.Context, req *computepb.PatchUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapResource() jsonReq, err := m.Marshal(body) @@ -558,11 +637,15 @@ func (c *urlMapsRESTClient) Patch(ctx context.Context, req *computepb.PatchUrlMa unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Update updates the specified UrlMap resource with the data included in the request. -func (c *urlMapsRESTClient) Update(ctx context.Context, req *computepb.UpdateUrlMapRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *urlMapsRESTClient) Update(ctx context.Context, req *computepb.UpdateUrlMapRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetUrlMapResource() jsonReq, err := m.Marshal(body) @@ -609,7 +692,11 @@ func (c *urlMapsRESTClient) Update(ctx context.Context, req *computepb.UpdateUrl unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Validate runs static validation for the UrlMap. In particular, the tests of the provided UrlMap will be run. Calling this method does NOT create the UrlMap. @@ -655,3 +742,56 @@ func (c *urlMapsRESTClient) Validate(ctx context.Context, req *computepb.Validat return rsp, unm.Unmarshal(buf, rsp) } + +// UrlMapsScopedListPair is a holder type for string/*computepb.UrlMapsScopedList map entries +type UrlMapsScopedListPair struct { + Key string + Value *computepb.UrlMapsScopedList +} + +// UrlMapsScopedListPairIterator manages a stream of UrlMapsScopedListPair. +type UrlMapsScopedListPairIterator struct { + items []UrlMapsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []UrlMapsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *UrlMapsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *UrlMapsScopedListPairIterator) Next() (UrlMapsScopedListPair, error) { + var item UrlMapsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *UrlMapsScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *UrlMapsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/url_maps_client_example_test.go b/compute/apiv1/url_maps_client_example_test.go index d6f8304d1e7..bc33fac6846 100644 --- a/compute/apiv1/url_maps_client_example_test.go +++ b/compute/apiv1/url_maps_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleUrlMapsClient_AggregatedList() { req := &computepb.AggregatedListUrlMapsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleUrlMapsClient_Delete() { @@ -141,12 +148,18 @@ func ExampleUrlMapsClient_List() { req := &computepb.ListUrlMapsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleUrlMapsClient_Patch() { diff --git a/compute/apiv1/vpn_gateways_client.go b/compute/apiv1/vpn_gateways_client.go index f1d9252e2a1..76879780d53 100644 --- a/compute/apiv1/vpn_gateways_client.go +++ b/compute/apiv1/vpn_gateways_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newVpnGatewaysClientHook clientHook @@ -53,13 +57,13 @@ type internalVpnGatewaysClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListVpnGatewaysRequest, ...gax.CallOption) (*computepb.VpnGatewayAggregatedList, error) - Delete(context.Context, *computepb.DeleteVpnGatewayRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListVpnGatewaysRequest, ...gax.CallOption) *VpnGatewaysScopedListPairIterator + Delete(context.Context, *computepb.DeleteVpnGatewayRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetVpnGatewayRequest, ...gax.CallOption) (*computepb.VpnGateway, error) GetStatus(context.Context, *computepb.GetStatusVpnGatewayRequest, ...gax.CallOption) (*computepb.VpnGatewaysGetStatusResponse, error) - Insert(context.Context, *computepb.InsertVpnGatewayRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListVpnGatewaysRequest, ...gax.CallOption) (*computepb.VpnGatewayList, error) - SetLabels(context.Context, *computepb.SetLabelsVpnGatewayRequest, ...gax.CallOption) (*computepb.Operation, error) + Insert(context.Context, *computepb.InsertVpnGatewayRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListVpnGatewaysRequest, ...gax.CallOption) *VpnGatewayIterator + SetLabels(context.Context, *computepb.SetLabelsVpnGatewayRequest, ...gax.CallOption) (*Operation, error) TestIamPermissions(context.Context, *computepb.TestIamPermissionsVpnGatewayRequest, ...gax.CallOption) (*computepb.TestPermissionsResponse, error) } @@ -98,12 +102,12 @@ func (c *VpnGatewaysClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of VPN gateways. -func (c *VpnGatewaysClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.VpnGatewayAggregatedList, error) { +func (c *VpnGatewaysClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListVpnGatewaysRequest, opts ...gax.CallOption) *VpnGatewaysScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified VPN gateway. -func (c *VpnGatewaysClient) Delete(ctx context.Context, req *computepb.DeleteVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *VpnGatewaysClient) Delete(ctx context.Context, req *computepb.DeleteVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -118,17 +122,17 @@ func (c *VpnGatewaysClient) GetStatus(ctx context.Context, req *computepb.GetSta } // Insert creates a VPN gateway in the specified project and region using the data included in the request. -func (c *VpnGatewaysClient) Insert(ctx context.Context, req *computepb.InsertVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *VpnGatewaysClient) Insert(ctx context.Context, req *computepb.InsertVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of VPN gateways available to the specified project and region. -func (c *VpnGatewaysClient) List(ctx context.Context, req *computepb.ListVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.VpnGatewayList, error) { +func (c *VpnGatewaysClient) List(ctx context.Context, req *computepb.ListVpnGatewaysRequest, opts ...gax.CallOption) *VpnGatewayIterator { return c.internalClient.List(ctx, req, opts...) } // SetLabels sets the labels on a VpnGateway. To learn more about labels, read the Labeling Resources documentation. -func (c *VpnGatewaysClient) SetLabels(ctx context.Context, req *computepb.SetLabelsVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *VpnGatewaysClient) SetLabels(ctx context.Context, req *computepb.SetLabelsVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.SetLabels(ctx, req, opts...) } @@ -202,66 +206,101 @@ func (c *vpnGatewaysRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of VPN gateways. -func (c *vpnGatewaysRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.VpnGatewayAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/vpnGateways", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *vpnGatewaysRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListVpnGatewaysRequest, opts ...gax.CallOption) *VpnGatewaysScopedListPairIterator { + it := &VpnGatewaysScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListVpnGatewaysRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.VpnGatewayAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]VpnGatewaysScopedListPair, string, error) { + resp := &computepb.VpnGatewayAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/vpnGateways", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]VpnGatewaysScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, VpnGatewaysScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified VPN gateway. -func (c *vpnGatewaysRESTClient) Delete(ctx context.Context, req *computepb.DeleteVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *vpnGatewaysRESTClient) Delete(ctx context.Context, req *computepb.DeleteVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/vpnGateways/%v", req.GetProject(), req.GetRegion(), req.GetVpnGateway()) @@ -301,7 +340,11 @@ func (c *vpnGatewaysRESTClient) Delete(ctx context.Context, req *computepb.Delet unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified VPN gateway. Gets a list of available VPN gateways by making a list() request. @@ -379,7 +422,7 @@ func (c *vpnGatewaysRESTClient) GetStatus(ctx context.Context, req *computepb.Ge } // Insert creates a VPN gateway in the specified project and region using the data included in the request. -func (c *vpnGatewaysRESTClient) Insert(ctx context.Context, req *computepb.InsertVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *vpnGatewaysRESTClient) Insert(ctx context.Context, req *computepb.InsertVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetVpnGatewayResource() jsonReq, err := m.Marshal(body) @@ -426,67 +469,99 @@ func (c *vpnGatewaysRESTClient) Insert(ctx context.Context, req *computepb.Inser unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of VPN gateways available to the specified project and region. -func (c *vpnGatewaysRESTClient) List(ctx context.Context, req *computepb.ListVpnGatewaysRequest, opts ...gax.CallOption) (*computepb.VpnGatewayList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/vpnGateways", req.GetProject(), req.GetRegion()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } + op := &Operation{proto: rsp} + return op, err +} +// List retrieves a list of VPN gateways available to the specified project and region. +func (c *vpnGatewaysRESTClient) List(ctx context.Context, req *computepb.ListVpnGatewaysRequest, opts ...gax.CallOption) *VpnGatewayIterator { + it := &VpnGatewayIterator{} + req = proto.Clone(req).(*computepb.ListVpnGatewaysRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.VpnGatewayList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.VpnGateway, string, error) { + resp := &computepb.VpnGatewayList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/vpnGateways", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // SetLabels sets the labels on a VpnGateway. To learn more about labels, read the Labeling Resources documentation. -func (c *vpnGatewaysRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsVpnGatewayRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *vpnGatewaysRESTClient) SetLabels(ctx context.Context, req *computepb.SetLabelsVpnGatewayRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetRegionSetLabelsRequestResource() jsonReq, err := m.Marshal(body) @@ -533,7 +608,11 @@ func (c *vpnGatewaysRESTClient) SetLabels(ctx context.Context, req *computepb.Se unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // TestIamPermissions returns permissions that a caller has on the specified resource. @@ -579,3 +658,103 @@ func (c *vpnGatewaysRESTClient) TestIamPermissions(ctx context.Context, req *com return rsp, unm.Unmarshal(buf, rsp) } + +// VpnGatewayIterator manages a stream of *computepb.VpnGateway. +type VpnGatewayIterator struct { + items []*computepb.VpnGateway + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.VpnGateway, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *VpnGatewayIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *VpnGatewayIterator) Next() (*computepb.VpnGateway, error) { + var item *computepb.VpnGateway + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *VpnGatewayIterator) bufLen() int { + return len(it.items) +} + +func (it *VpnGatewayIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} + +// VpnGatewaysScopedListPair is a holder type for string/*computepb.VpnGatewaysScopedList map entries +type VpnGatewaysScopedListPair struct { + Key string + Value *computepb.VpnGatewaysScopedList +} + +// VpnGatewaysScopedListPairIterator manages a stream of VpnGatewaysScopedListPair. +type VpnGatewaysScopedListPairIterator struct { + items []VpnGatewaysScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []VpnGatewaysScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *VpnGatewaysScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *VpnGatewaysScopedListPairIterator) Next() (VpnGatewaysScopedListPair, error) { + var item VpnGatewaysScopedListPair + if err := it.nextFunc(); err != nil { + return item, err + } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} + +func (it *VpnGatewaysScopedListPairIterator) bufLen() int { + return len(it.items) +} + +func (it *VpnGatewaysScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} diff --git a/compute/apiv1/vpn_gateways_client_example_test.go b/compute/apiv1/vpn_gateways_client_example_test.go index 74b8ecf2f1a..bfe8ae8575a 100644 --- a/compute/apiv1/vpn_gateways_client_example_test.go +++ b/compute/apiv1/vpn_gateways_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleVpnGatewaysClient_AggregatedList() { req := &computepb.AggregatedListVpnGatewaysRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleVpnGatewaysClient_Delete() { @@ -141,12 +148,18 @@ func ExampleVpnGatewaysClient_List() { req := &computepb.ListVpnGatewaysRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleVpnGatewaysClient_SetLabels() { diff --git a/compute/apiv1/vpn_tunnels_client.go b/compute/apiv1/vpn_tunnels_client.go index 1bbf3603449..e53f6745b4a 100644 --- a/compute/apiv1/vpn_tunnels_client.go +++ b/compute/apiv1/vpn_tunnels_client.go @@ -21,10 +21,13 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" + "sort" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -32,6 +35,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newVpnTunnelsClientHook clientHook @@ -50,11 +54,11 @@ type internalVpnTunnelsClient interface { Close() error setGoogleClientInfo(...string) Connection() *grpc.ClientConn - AggregatedList(context.Context, *computepb.AggregatedListVpnTunnelsRequest, ...gax.CallOption) (*computepb.VpnTunnelAggregatedList, error) - Delete(context.Context, *computepb.DeleteVpnTunnelRequest, ...gax.CallOption) (*computepb.Operation, error) + AggregatedList(context.Context, *computepb.AggregatedListVpnTunnelsRequest, ...gax.CallOption) *VpnTunnelsScopedListPairIterator + Delete(context.Context, *computepb.DeleteVpnTunnelRequest, ...gax.CallOption) (*Operation, error) Get(context.Context, *computepb.GetVpnTunnelRequest, ...gax.CallOption) (*computepb.VpnTunnel, error) - Insert(context.Context, *computepb.InsertVpnTunnelRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListVpnTunnelsRequest, ...gax.CallOption) (*computepb.VpnTunnelList, error) + Insert(context.Context, *computepb.InsertVpnTunnelRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListVpnTunnelsRequest, ...gax.CallOption) *VpnTunnelIterator } // VpnTunnelsClient is a client for interacting with Google Compute Engine API. @@ -92,12 +96,12 @@ func (c *VpnTunnelsClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of VPN tunnels. -func (c *VpnTunnelsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListVpnTunnelsRequest, opts ...gax.CallOption) (*computepb.VpnTunnelAggregatedList, error) { +func (c *VpnTunnelsClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListVpnTunnelsRequest, opts ...gax.CallOption) *VpnTunnelsScopedListPairIterator { return c.internalClient.AggregatedList(ctx, req, opts...) } // Delete deletes the specified VpnTunnel resource. -func (c *VpnTunnelsClient) Delete(ctx context.Context, req *computepb.DeleteVpnTunnelRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *VpnTunnelsClient) Delete(ctx context.Context, req *computepb.DeleteVpnTunnelRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Delete(ctx, req, opts...) } @@ -107,12 +111,12 @@ func (c *VpnTunnelsClient) Get(ctx context.Context, req *computepb.GetVpnTunnelR } // Insert creates a VpnTunnel resource in the specified project and region using the data included in the request. -func (c *VpnTunnelsClient) Insert(ctx context.Context, req *computepb.InsertVpnTunnelRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *VpnTunnelsClient) Insert(ctx context.Context, req *computepb.InsertVpnTunnelRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Insert(ctx, req, opts...) } // List retrieves a list of VpnTunnel resources contained in the specified project and region. -func (c *VpnTunnelsClient) List(ctx context.Context, req *computepb.ListVpnTunnelsRequest, opts ...gax.CallOption) (*computepb.VpnTunnelList, error) { +func (c *VpnTunnelsClient) List(ctx context.Context, req *computepb.ListVpnTunnelsRequest, opts ...gax.CallOption) *VpnTunnelIterator { return c.internalClient.List(ctx, req, opts...) } @@ -181,66 +185,101 @@ func (c *vpnTunnelsRESTClient) Connection() *grpc.ClientConn { } // AggregatedList retrieves an aggregated list of VPN tunnels. -func (c *vpnTunnelsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListVpnTunnelsRequest, opts ...gax.CallOption) (*computepb.VpnTunnelAggregatedList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/vpnTunnels", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.IncludeAllScopes != nil { - params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() - - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } - - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err - } - +func (c *vpnTunnelsRESTClient) AggregatedList(ctx context.Context, req *computepb.AggregatedListVpnTunnelsRequest, opts ...gax.CallOption) *VpnTunnelsScopedListPairIterator { + it := &VpnTunnelsScopedListPairIterator{} + req = proto.Clone(req).(*computepb.AggregatedListVpnTunnelsRequest) unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.VpnTunnelAggregatedList{} - - return rsp, unm.Unmarshal(buf, rsp) + it.InternalFetch = func(pageSize int, pageToken string) ([]VpnTunnelsScopedListPair, string, error) { + resp := &computepb.VpnTunnelAggregatedList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/aggregated/vpnTunnels", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.IncludeAllScopes != nil { + params.Add("includeAllScopes", fmt.Sprintf("%v", req.GetIncludeAllScopes())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + + elems := make([]VpnTunnelsScopedListPair, 0, len(resp.GetItems())) + for k, v := range resp.GetItems() { + elems = append(elems, VpnTunnelsScopedListPair{k, v}) + } + sort.Slice(elems, func(i, j int) bool { return elems[i].Key < elems[j].Key }) + + return elems, resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it } // Delete deletes the specified VpnTunnel resource. -func (c *vpnTunnelsRESTClient) Delete(ctx context.Context, req *computepb.DeleteVpnTunnelRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *vpnTunnelsRESTClient) Delete(ctx context.Context, req *computepb.DeleteVpnTunnelRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/vpnTunnels/%v", req.GetProject(), req.GetRegion(), req.GetVpnTunnel()) @@ -280,7 +319,11 @@ func (c *vpnTunnelsRESTClient) Delete(ctx context.Context, req *computepb.Delete unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // Get returns the specified VpnTunnel resource. Gets a list of available VPN tunnels by making a list() request. @@ -321,7 +364,7 @@ func (c *vpnTunnelsRESTClient) Get(ctx context.Context, req *computepb.GetVpnTun } // Insert creates a VpnTunnel resource in the specified project and region using the data included in the request. -func (c *vpnTunnelsRESTClient) Insert(ctx context.Context, req *computepb.InsertVpnTunnelRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *vpnTunnelsRESTClient) Insert(ctx context.Context, req *computepb.InsertVpnTunnelRequest, opts ...gax.CallOption) (*Operation, error) { m := protojson.MarshalOptions{AllowPartial: true} body := req.GetVpnTunnelResource() jsonReq, err := m.Marshal(body) @@ -368,61 +411,193 @@ func (c *vpnTunnelsRESTClient) Insert(ctx context.Context, req *computepb.Insert unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } // List retrieves a list of VpnTunnel resources contained in the specified project and region. -func (c *vpnTunnelsRESTClient) List(ctx context.Context, req *computepb.ListVpnTunnelsRequest, opts ...gax.CallOption) (*computepb.VpnTunnelList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/vpnTunnels", req.GetProject(), req.GetRegion()) +func (c *vpnTunnelsRESTClient) List(ctx context.Context, req *computepb.ListVpnTunnelsRequest, opts ...gax.CallOption) *VpnTunnelIterator { + it := &VpnTunnelIterator{} + req = proto.Clone(req).(*computepb.ListVpnTunnelsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.VpnTunnel, string, error) { + resp := &computepb.VpnTunnelList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/regions/%v/vpnTunnels", req.GetProject(), req.GetRegion()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil + } + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil + } + + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() + + return it +} - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } +// VpnTunnelIterator manages a stream of *computepb.VpnTunnel. +type VpnTunnelIterator struct { + items []*computepb.VpnTunnel + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.VpnTunnel, nextPageToken string, err error) +} - baseUrl.RawQuery = params.Encode() +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *VpnTunnelIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *VpnTunnelIterator) Next() (*computepb.VpnTunnel, error) { + var item *computepb.VpnTunnel + if err := it.nextFunc(); err != nil { + return item, err } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +func (it *VpnTunnelIterator) bufLen() int { + return len(it.items) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +func (it *VpnTunnelIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// VpnTunnelsScopedListPair is a holder type for string/*computepb.VpnTunnelsScopedList map entries +type VpnTunnelsScopedListPair struct { + Key string + Value *computepb.VpnTunnelsScopedList +} + +// VpnTunnelsScopedListPairIterator manages a stream of VpnTunnelsScopedListPair. +type VpnTunnelsScopedListPairIterator struct { + items []VpnTunnelsScopedListPair + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []VpnTunnelsScopedListPair, nextPageToken string, err error) +} + +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *VpnTunnelsScopedListPairIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} + +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *VpnTunnelsScopedListPairIterator) Next() (VpnTunnelsScopedListPair, error) { + var item VpnTunnelsScopedListPair + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.VpnTunnelList{} +func (it *VpnTunnelsScopedListPairIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *VpnTunnelsScopedListPairIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/vpn_tunnels_client_example_test.go b/compute/apiv1/vpn_tunnels_client_example_test.go index d5354e683ee..bd4da7c5c7b 100644 --- a/compute/apiv1/vpn_tunnels_client_example_test.go +++ b/compute/apiv1/vpn_tunnels_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -46,12 +47,18 @@ func ExampleVpnTunnelsClient_AggregatedList() { req := &computepb.AggregatedListVpnTunnelsRequest{ // TODO: Fill request struct fields. } - resp, err := c.AggregatedList(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.AggregatedList(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleVpnTunnelsClient_Delete() { @@ -122,10 +129,16 @@ func ExampleVpnTunnelsClient_List() { req := &computepb.ListVpnTunnelsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/compute/apiv1/zone_operations_client.go b/compute/apiv1/zone_operations_client.go index cb8b95c4a5c..e5b1bede1c4 100644 --- a/compute/apiv1/zone_operations_client.go +++ b/compute/apiv1/zone_operations_client.go @@ -20,10 +20,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +33,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newZoneOperationsClientHook clientHook @@ -49,9 +52,9 @@ type internalZoneOperationsClient interface { setGoogleClientInfo(...string) Connection() *grpc.ClientConn Delete(context.Context, *computepb.DeleteZoneOperationRequest, ...gax.CallOption) (*computepb.DeleteZoneOperationResponse, error) - Get(context.Context, *computepb.GetZoneOperationRequest, ...gax.CallOption) (*computepb.Operation, error) - List(context.Context, *computepb.ListZoneOperationsRequest, ...gax.CallOption) (*computepb.OperationList, error) - Wait(context.Context, *computepb.WaitZoneOperationRequest, ...gax.CallOption) (*computepb.Operation, error) + Get(context.Context, *computepb.GetZoneOperationRequest, ...gax.CallOption) (*Operation, error) + List(context.Context, *computepb.ListZoneOperationsRequest, ...gax.CallOption) *OperationIterator + Wait(context.Context, *computepb.WaitZoneOperationRequest, ...gax.CallOption) (*Operation, error) } // ZoneOperationsClient is a client for interacting with Google Compute Engine API. @@ -94,12 +97,12 @@ func (c *ZoneOperationsClient) Delete(ctx context.Context, req *computepb.Delete } // Get retrieves the specified zone-specific Operations resource. -func (c *ZoneOperationsClient) Get(ctx context.Context, req *computepb.GetZoneOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ZoneOperationsClient) Get(ctx context.Context, req *computepb.GetZoneOperationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Get(ctx, req, opts...) } // List retrieves a list of Operation resources contained within the specified zone. -func (c *ZoneOperationsClient) List(ctx context.Context, req *computepb.ListZoneOperationsRequest, opts ...gax.CallOption) (*computepb.OperationList, error) { +func (c *ZoneOperationsClient) List(ctx context.Context, req *computepb.ListZoneOperationsRequest, opts ...gax.CallOption) *OperationIterator { return c.internalClient.List(ctx, req, opts...) } @@ -110,7 +113,7 @@ func (c *ZoneOperationsClient) List(ctx context.Context, req *computepb.ListZone // In uncommon cases, when the server is overloaded, the request might return before the default deadline is reached, or might return after zero seconds. // // If the default deadline is reached, there is no guarantee that the operation is actually done when the method returns. Be prepared to retry if the operation is not DONE. -func (c *ZoneOperationsClient) Wait(ctx context.Context, req *computepb.WaitZoneOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *ZoneOperationsClient) Wait(ctx context.Context, req *computepb.WaitZoneOperationRequest, opts ...gax.CallOption) (*Operation, error) { return c.internalClient.Wait(ctx, req, opts...) } @@ -216,7 +219,7 @@ func (c *zoneOperationsRESTClient) Delete(ctx context.Context, req *computepb.De } // Get retrieves the specified zone-specific Operations resource. -func (c *zoneOperationsRESTClient) Get(ctx context.Context, req *computepb.GetZoneOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *zoneOperationsRESTClient) Get(ctx context.Context, req *computepb.GetZoneOperationRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/operations/%v", req.GetProject(), req.GetZone(), req.GetOperation()) @@ -249,63 +252,95 @@ func (c *zoneOperationsRESTClient) Get(ctx context.Context, req *computepb.GetZo unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) -} - -// List retrieves a list of Operation resources contained within the specified zone. -func (c *zoneOperationsRESTClient) List(ctx context.Context, req *computepb.ListZoneOperationsRequest, opts ...gax.CallOption) (*computepb.OperationList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/operations", req.GetProject(), req.GetZone()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) - } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) - } - - baseUrl.RawQuery = params.Encode() - - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} - - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { + if err := unm.Unmarshal(buf, rsp); err != nil { return nil, err } - defer httpRsp.Body.Close() + op := &Operation{proto: rsp} + return op, err +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) +// List retrieves a list of Operation resources contained within the specified zone. +func (c *zoneOperationsRESTClient) List(ctx context.Context, req *computepb.ListZoneOperationsRequest, opts ...gax.CallOption) *OperationIterator { + it := &OperationIterator{} + req = proto.Clone(req).(*computepb.ListZoneOperationsRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Operation, string, error) { + resp := &computepb.OperationList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/operations", req.GetProject(), req.GetZone()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.OperationList{} + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - return rsp, unm.Unmarshal(buf, rsp) + return it } // Wait waits for the specified Operation resource to return as DONE or for the request to approach the 2 minute deadline, and retrieves the specified Operation resource. This method differs from the GET method in that it waits for no more than the default deadline (2 minutes) and then returns the current state of the operation, which might be DONE or still in progress. @@ -315,7 +350,7 @@ func (c *zoneOperationsRESTClient) List(ctx context.Context, req *computepb.List // In uncommon cases, when the server is overloaded, the request might return before the default deadline is reached, or might return after zero seconds. // // If the default deadline is reached, there is no guarantee that the operation is actually done when the method returns. Be prepared to retry if the operation is not DONE. -func (c *zoneOperationsRESTClient) Wait(ctx context.Context, req *computepb.WaitZoneOperationRequest, opts ...gax.CallOption) (*computepb.Operation, error) { +func (c *zoneOperationsRESTClient) Wait(ctx context.Context, req *computepb.WaitZoneOperationRequest, opts ...gax.CallOption) (*Operation, error) { baseUrl, _ := url.Parse(c.endpoint) baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones/%v/operations/%v/wait", req.GetProject(), req.GetZone(), req.GetOperation()) @@ -348,5 +383,9 @@ func (c *zoneOperationsRESTClient) Wait(ctx context.Context, req *computepb.Wait unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} rsp := &computepb.Operation{} - return rsp, unm.Unmarshal(buf, rsp) + if err := unm.Unmarshal(buf, rsp); err != nil { + return nil, err + } + op := &Operation{proto: rsp} + return op, err } diff --git a/compute/apiv1/zone_operations_client_example_test.go b/compute/apiv1/zone_operations_client_example_test.go index f7f1c346c63..7ed519fa95d 100644 --- a/compute/apiv1/zone_operations_client_example_test.go +++ b/compute/apiv1/zone_operations_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -84,12 +85,18 @@ func ExampleZoneOperationsClient_List() { req := &computepb.ListZoneOperationsRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } func ExampleZoneOperationsClient_Wait() { diff --git a/compute/apiv1/zones_client.go b/compute/apiv1/zones_client.go index 96d6a8d1a6d..0b23e6dc0da 100644 --- a/compute/apiv1/zones_client.go +++ b/compute/apiv1/zones_client.go @@ -20,10 +20,12 @@ import ( "context" "fmt" "io/ioutil" + "math" "net/http" "net/url" gax "github.com/googleapis/gax-go/v2" + "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/api/option/internaloption" httptransport "google.golang.org/api/transport/http" @@ -31,6 +33,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/encoding/protojson" + "google.golang.org/protobuf/proto" ) var newZonesClientHook clientHook @@ -47,7 +50,7 @@ type internalZonesClient interface { setGoogleClientInfo(...string) Connection() *grpc.ClientConn Get(context.Context, *computepb.GetZoneRequest, ...gax.CallOption) (*computepb.Zone, error) - List(context.Context, *computepb.ListZonesRequest, ...gax.CallOption) (*computepb.ZoneList, error) + List(context.Context, *computepb.ListZonesRequest, ...gax.CallOption) *ZoneIterator } // ZonesClient is a client for interacting with Google Compute Engine API. @@ -90,7 +93,7 @@ func (c *ZonesClient) Get(ctx context.Context, req *computepb.GetZoneRequest, op } // List retrieves the list of Zone resources available to the specified project. -func (c *ZonesClient) List(ctx context.Context, req *computepb.ListZonesRequest, opts ...gax.CallOption) (*computepb.ZoneList, error) { +func (c *ZonesClient) List(ctx context.Context, req *computepb.ListZonesRequest, opts ...gax.CallOption) *ZoneIterator { return c.internalClient.List(ctx, req, opts...) } @@ -196,57 +199,132 @@ func (c *zonesRESTClient) Get(ctx context.Context, req *computepb.GetZoneRequest } // List retrieves the list of Zone resources available to the specified project. -func (c *zonesRESTClient) List(ctx context.Context, req *computepb.ListZonesRequest, opts ...gax.CallOption) (*computepb.ZoneList, error) { - baseUrl, _ := url.Parse(c.endpoint) - baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones", req.GetProject()) - - params := url.Values{} - if req != nil && req.Filter != nil { - params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) - } - if req != nil && req.MaxResults != nil { - params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) - } - if req != nil && req.OrderBy != nil { - params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) - } - if req != nil && req.PageToken != nil { - params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) +func (c *zonesRESTClient) List(ctx context.Context, req *computepb.ListZonesRequest, opts ...gax.CallOption) *ZoneIterator { + it := &ZoneIterator{} + req = proto.Clone(req).(*computepb.ListZonesRequest) + unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} + it.InternalFetch = func(pageSize int, pageToken string) ([]*computepb.Zone, string, error) { + resp := &computepb.ZoneList{} + if pageToken != "" { + req.PageToken = proto.String(pageToken) + } + if pageSize > math.MaxInt32 { + req.MaxResults = proto.Uint32(math.MaxInt32) + } else if pageSize != 0 { + req.MaxResults = proto.Uint32(uint32(pageSize)) + } + baseUrl, _ := url.Parse(c.endpoint) + baseUrl.Path += fmt.Sprintf("/compute/v1/projects/%v/zones", req.GetProject()) + + params := url.Values{} + if req != nil && req.Filter != nil { + params.Add("filter", fmt.Sprintf("%v", req.GetFilter())) + } + if req != nil && req.MaxResults != nil { + params.Add("maxResults", fmt.Sprintf("%v", req.GetMaxResults())) + } + if req != nil && req.OrderBy != nil { + params.Add("orderBy", fmt.Sprintf("%v", req.GetOrderBy())) + } + if req != nil && req.PageToken != nil { + params.Add("pageToken", fmt.Sprintf("%v", req.GetPageToken())) + } + if req != nil && req.ReturnPartialSuccess != nil { + params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + } + + baseUrl.RawQuery = params.Encode() + + httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) + if err != nil { + return nil, "", err + } + + // Set the headers + for k, v := range c.xGoogMetadata { + httpReq.Header[k] = v + } + + httpReq.Header["Content-Type"] = []string{"application/json"} + httpRsp, err := c.httpClient.Do(httpReq) + if err != nil { + return nil, "", err + } + defer httpRsp.Body.Close() + + if httpRsp.StatusCode != http.StatusOK { + return nil, "", fmt.Errorf(httpRsp.Status) + } + + buf, err := ioutil.ReadAll(httpRsp.Body) + if err != nil { + return nil, "", err + } + + unm.Unmarshal(buf, resp) + it.Response = resp + return resp.GetItems(), resp.GetNextPageToken(), nil } - if req != nil && req.ReturnPartialSuccess != nil { - params.Add("returnPartialSuccess", fmt.Sprintf("%v", req.GetReturnPartialSuccess())) + + fetch := func(pageSize int, pageToken string) (string, error) { + items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) + if err != nil { + return "", err + } + it.items = append(it.items, items...) + return nextPageToken, nil } - baseUrl.RawQuery = params.Encode() + it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) + it.pageInfo.MaxSize = int(req.GetMaxResults()) + it.pageInfo.Token = req.GetPageToken() - httpReq, err := http.NewRequest("GET", baseUrl.String(), nil) - if err != nil { - return nil, err - } - httpReq = httpReq.WithContext(ctx) - // Set the headers - for k, v := range c.xGoogMetadata { - httpReq.Header[k] = v - } - httpReq.Header["Content-Type"] = []string{"application/json"} + return it +} - httpRsp, err := c.httpClient.Do(httpReq) - if err != nil { - return nil, err - } - defer httpRsp.Body.Close() +// ZoneIterator manages a stream of *computepb.Zone. +type ZoneIterator struct { + items []*computepb.Zone + pageInfo *iterator.PageInfo + nextFunc func() error + + // Response is the raw response for the current page. + // It must be cast to the RPC response type. + // Calling Next() or InternalFetch() updates this value. + Response interface{} + + // InternalFetch is for use by the Google Cloud Libraries only. + // It is not part of the stable interface of this package. + // + // InternalFetch returns results from a single call to the underlying RPC. + // The number of results is no greater than pageSize. + // If there are no more results, nextPageToken is empty and err is nil. + InternalFetch func(pageSize int, pageToken string) (results []*computepb.Zone, nextPageToken string, err error) +} - if httpRsp.StatusCode != http.StatusOK { - return nil, fmt.Errorf(httpRsp.Status) - } +// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. +func (it *ZoneIterator) PageInfo() *iterator.PageInfo { + return it.pageInfo +} - buf, err := ioutil.ReadAll(httpRsp.Body) - if err != nil { - return nil, err +// Next returns the next result. Its second return value is iterator.Done if there are no more +// results. Once Next returns Done, all subsequent calls will return Done. +func (it *ZoneIterator) Next() (*computepb.Zone, error) { + var item *computepb.Zone + if err := it.nextFunc(); err != nil { + return item, err } + item = it.items[0] + it.items = it.items[1:] + return item, nil +} - unm := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true} - rsp := &computepb.ZoneList{} +func (it *ZoneIterator) bufLen() int { + return len(it.items) +} - return rsp, unm.Unmarshal(buf, rsp) +func (it *ZoneIterator) takeBuf() interface{} { + b := it.items + it.items = nil + return b } diff --git a/compute/apiv1/zones_client_example_test.go b/compute/apiv1/zones_client_example_test.go index 109f4704bb8..f834295751d 100644 --- a/compute/apiv1/zones_client_example_test.go +++ b/compute/apiv1/zones_client_example_test.go @@ -20,6 +20,7 @@ import ( "context" compute "cloud.google.com/go/compute/apiv1" + "google.golang.org/api/iterator" computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" ) @@ -65,10 +66,16 @@ func ExampleZonesClient_List() { req := &computepb.ListZonesRequest{ // TODO: Fill request struct fields. } - resp, err := c.List(ctx, req) - if err != nil { - // TODO: Handle error. + it := c.List(ctx, req) + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + // TODO: Handle error. + } + // TODO: Use resp. + _ = resp } - // TODO: Use resp. - _ = resp } diff --git a/internal/gapicgen/cmd/genbot/Dockerfile b/internal/gapicgen/cmd/genbot/Dockerfile index 3d0d8bc63af..a225f63dbda 100644 --- a/internal/gapicgen/cmd/genbot/Dockerfile +++ b/internal/gapicgen/cmd/genbot/Dockerfile @@ -27,7 +27,7 @@ RUN go install github.com/golang/protobuf/protoc-gen-go@v1.5.2 && \ go install golang.org/x/lint/golint@latest && \ go install golang.org/x/tools/cmd/goimports@latest && \ go install honnef.co/go/tools/cmd/staticcheck@latest && \ - go install github.com/googleapis/gapic-generator-go/cmd/protoc-gen-go_gapic@v0.21.8 + go install github.com/googleapis/gapic-generator-go/cmd/protoc-gen-go_gapic@v0.22.0 ENV PATH="${PATH}:/root/go/bin" # Source: http://debuggable.com/posts/disable-strict-host-checking-for-git-clone:49896ff3-0ac0-4263-9703-1eae4834cda3 diff --git a/internal/gapicgen/generator/gapics.go b/internal/gapicgen/generator/gapics.go index 9856accb9e0..539929a1839 100644 --- a/internal/gapicgen/generator/gapics.go +++ b/internal/gapicgen/generator/gapics.go @@ -310,6 +310,9 @@ func (g *GapicGenerator) microgen(conf *microgenConfig) error { if len(conf.transports) > 0 { args = append(args, "--go_gapic_opt", fmt.Sprintf("transport=%s", strings.Join(conf.transports, "+"))) } + if conf.googleapisDiscovery { + args = append(args, "--go_gapic_opt", "diregapic") + } args = append(args, protoFiles...) c := execv.Command("protoc", args...) c.Dir = dir