Skip to content

Commit

Permalink
feat(HMS-2248): Add token support for list template
Browse files Browse the repository at this point in the history
  • Loading branch information
adiabramovitch committed Aug 30, 2023
1 parent 47e5cea commit ce06412
Show file tree
Hide file tree
Showing 20 changed files with 218 additions and 91 deletions.
44 changes: 41 additions & 3 deletions api/openapi.gen.json
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,14 @@
"id": "lt-9843797432897342",
"name": "XXL large backend API"
}
]
],
"links": {
"next": "",
"previous": ""
},
"metadata": {
"total": 0
}
}
},
"v1.NoopReservationResponsePayloadExample": {
Expand Down Expand Up @@ -1052,6 +1059,25 @@
"type": "object"
},
"type": "array"
},
"links": {
"properties": {
"next": {
"type": "string"
},
"previous": {
"type": "string"
}
},
"type": "object"
},
"metadata": {
"properties": {
"total": {
"type": "integer"
}
},
"type": "object"
}
},
"type": "object"
Expand Down Expand Up @@ -1284,7 +1310,7 @@
"name": "GPL-3.0"
},
"title": "provisioning-api",
"version": "1.5.0"
"version": "1.6.0"
},
"openapi": "3.0.0",
"paths": {
Expand Down Expand Up @@ -2042,7 +2068,7 @@
},
"/sources/{ID}/launch_templates": {
"get": {
"description": "Return a list of launch templates.\nA launch template is a configuration set with a name that is available through hyperscaler API. When creating reservations, launch template can be provided in order to set additional configuration for instances.\nCurrently only AWS Launch Templates are supported.\n",
"description": "Return a list of launch templates.\nA launch template is a configuration set with a name that is available through hyperscaler API. When creating reservations, launch template can be provided in order to set additional configuration for instances. In GCP, when using templates, propagated user attributes are not overridden or updated. Only new attributes are added to the instance.\nCurrently AWS and GCP Launch Templates are supported.\n",
"operationId": "getLaunchTemplatesList",
"parameters": [
{
Expand All @@ -2063,6 +2089,18 @@
"schema": {
"type": "string"
}
},
{
"description": "The token to request the next page of results, empty token for first page.",
"in": "query",
"name": "token",
"schema": {
"default": "",
"type": "string"
}
},
{
"$ref": "#/components/parameters/Limit"
}
],
"responses": {
Expand Down
30 changes: 27 additions & 3 deletions api/openapi.gen.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,18 @@ components:
type: string
name:
type: string
links:
type: object
properties:
next:
type: string
previous:
type: string
metadata:
type: object
properties:
total:
type: integer
v1.ListPubkeyResponse:
type: object
properties:
Expand Down Expand Up @@ -826,6 +838,11 @@ components:
data:
- id: lt-9843797432897342
name: XXL large backend API
links:
next: ""
previous: ""
metadata:
total: 0
v1.NoopReservationResponsePayloadExample:
value:
reservation_id: 1310
Expand Down Expand Up @@ -894,7 +911,7 @@ info:
description: Provisioning service API
license:
name: GPL-3.0
version: 1.5.0
version: 1.6.0
paths:
/availability_status/sources:
post:
Expand Down Expand Up @@ -1387,8 +1404,8 @@ paths:
- Source
description: |
Return a list of launch templates.
A launch template is a configuration set with a name that is available through hyperscaler API. When creating reservations, launch template can be provided in order to set additional configuration for instances.
Currently only AWS Launch Templates are supported.
A launch template is a configuration set with a name that is available through hyperscaler API. When creating reservations, launch template can be provided in order to set additional configuration for instances. In GCP, when using templates, propagated user attributes are not overridden or updated. Only new attributes are added to the instance.
Currently AWS and GCP Launch Templates are supported.
operationId: getLaunchTemplatesList
parameters:
- name: ID
Expand All @@ -1404,6 +1421,13 @@ paths:
required: true
schema:
type: string
- name: token
in: query
description: The token to request the next page of results, empty token for first page.
schema:
type: string
default: ""
- $ref: '#/components/parameters/Limit'
responses:
"200":
description: Return on success.
Expand Down
2 changes: 1 addition & 1 deletion cmd/spec/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.5.0
1.6.0
9 changes: 8 additions & 1 deletion cmd/spec/example_templates.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package main

import "github.com/RHEnVision/provisioning-backend/internal/payloads"
import (
"github.com/RHEnVision/provisioning-backend/internal/page"
"github.com/RHEnVision/provisioning-backend/internal/payloads"
)

var LaunchTemplateListResponse = payloads.LaunchTemplateListResponse{
Data: []*payloads.LaunchTemplateResponse{
Expand All @@ -9,4 +12,8 @@ var LaunchTemplateListResponse = payloads.LaunchTemplateListResponse{
Name: "XXL large backend API",
},
},
Metadata: page.Metadata{},
Links: page.Links{
Next: "",
},
}
14 changes: 12 additions & 2 deletions cmd/spec/path.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,10 @@ paths:
A launch template is a configuration set with a name that is available through hyperscaler
API. When creating reservations, launch template can be provided in order to set additional
configuration for instances.
Currently only AWS Launch Templates are supported.
In GCP, when using templates, propagated user attributes are not overridden or updated.
Only new attributes are added to the instance.
Currently AWS and GCP Launch Templates are supported.
operationId: getLaunchTemplatesList
tags:
- Source
Expand All @@ -280,6 +282,14 @@ paths:
type: string
required: true
description: Hyperscaler region
- in: query
name: token
schema:
type: string
default: ""
required: false
description: The token to request the next page of results, empty token for first page.
- $ref: '#/components/parameters/Limit'
responses:
'200':
description: Return on success.
Expand Down
46 changes: 25 additions & 21 deletions internal/clients/http/ec2/ec2_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/RHEnVision/provisioning-backend/internal/clients/http"
"github.com/RHEnVision/provisioning-backend/internal/config"
"github.com/RHEnVision/provisioning-backend/internal/models"
"github.com/RHEnVision/provisioning-backend/internal/page"
"github.com/RHEnVision/provisioning-backend/internal/ptr"
"github.com/RHEnVision/provisioning-backend/internal/telemetry"
"github.com/aws/aws-sdk-go-v2/aws"
Expand Down Expand Up @@ -338,34 +339,37 @@ func (c *ec2Client) DescribeInstanceDetails(ctx context.Context, InstanceIds []s
return instanceDetailList, nil
}

func (c *ec2Client) ListLaunchTemplates(ctx context.Context) ([]*clients.LaunchTemplate, error) {
func (c *ec2Client) ListLaunchTemplates(ctx context.Context) ([]*clients.LaunchTemplate, *string, error) {
ctx, span := otel.Tracer(TraceName).Start(ctx, "ListLaunchTemplates")
defer span.End()

input := &ec2.DescribeLaunchTemplatesInput{MaxResults: ptr.ToInt32(100)}
pag := ec2.NewDescribeLaunchTemplatesPaginator(c.ec2, input)
limit := page.Limit(ctx).Int32()
input := &ec2.DescribeLaunchTemplatesInput{
MaxResults: &limit,
NextToken: ptr.To(page.Token(ctx)),
}

var res []*clients.LaunchTemplate
for pag.HasMorePages() {
resp, err := pag.NextPage(ctx)
if err != nil {
if isAWSUnauthorizedError(err) {
err = clients.UnauthorizedErr
}
span.SetStatus(codes.Error, err.Error())
return nil, fmt.Errorf("cannot list launch templates: %w", err)
resp, err := c.ec2.DescribeLaunchTemplates(ctx, input)
if err != nil {
if isAWSUnauthorizedError(err) {
err = clients.UnauthorizedErr
}

for _, awsTemplate := range resp.LaunchTemplates {
t := clients.LaunchTemplate{
ID: ptr.From(awsTemplate.LaunchTemplateId),
Name: ptr.From(awsTemplate.LaunchTemplateName),
}
res = append(res, &t)
span.SetStatus(codes.Error, err.Error())
return nil, nil, fmt.Errorf("cannot list launch templates: %w", err)
}
res := make([]*clients.LaunchTemplate, 0, len(resp.LaunchTemplates))
for _, awsTemplate := range resp.LaunchTemplates {
t := clients.LaunchTemplate{
ID: ptr.From(awsTemplate.LaunchTemplateId),
Name: ptr.From(awsTemplate.LaunchTemplateName),
}
res = append(res, &t)
}

return res, nil
nextToken := resp.NextToken
if nextToken == nil {
nextToken = ptr.To("")
}
return res, nextToken, nil
}

func (c *ec2Client) RunInstances(ctx context.Context, params *clients.AWSInstanceParams, amount int32, name *string, reservation *models.AWSReservation) ([]*string, *string, error) {
Expand Down
45 changes: 22 additions & 23 deletions internal/clients/http/gcp/gcp_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/RHEnVision/provisioning-backend/internal/logging"
"github.com/RHEnVision/provisioning-backend/internal/models"
"github.com/RHEnVision/provisioning-backend/internal/page"
"github.com/RHEnVision/provisioning-backend/internal/telemetry"

compute "cloud.google.com/go/compute/apiv1"
Expand Down Expand Up @@ -100,44 +101,42 @@ func (c *gcpClient) NewInstanceTemplatesClient(ctx context.Context) (*compute.In
return client, nil
}

func (c *gcpClient) ListLaunchTemplates(ctx context.Context) ([]*clients.LaunchTemplate, error) {
func (c *gcpClient) ListLaunchTemplates(ctx context.Context) ([]*clients.LaunchTemplate, *string, error) {
ctx, span := otel.Tracer(TraceName).Start(ctx, "ListLaunchTemplates")
defer span.End()

var token string
logger := logger(ctx)
logger.Trace().Msgf("Listing launch templates")

templatesClient, err := c.NewInstanceTemplatesClient(ctx)
if err != nil {
logger.Error().Err(err).Msg("Could not get instances client")
return nil, fmt.Errorf("unable to get instances client: %w", err)
return nil, nil, fmt.Errorf("unable to get instances client: %w", err)
}
defer templatesClient.Close()

req := &computepb.AggregatedListInstanceTemplatesRequest{
Project: c.auth.Payload,
limit := page.Limit(ctx).Int()
req := &computepb.ListInstanceTemplatesRequest{
Project: c.auth.Payload,
MaxResults: ptr.To(uint32(limit)),
PageToken: ptr.To(page.Token(ctx)),
}

var templatesList []*clients.LaunchTemplate
templates := templatesClient.AggregatedList(ctx, req)
for {
pair, err := templates.Next()
if errors.Is(err, iterator.Done) {
break
} else if err != nil {
logger.Error().Err(err).Msg("An error occurred during listing launch templates")
span.SetStatus(codes.Error, err.Error())
return nil, fmt.Errorf("cannot list launch templates: %w", err)
} else {
instancesTemplates := pair.Value.InstanceTemplates
for _, template := range instancesTemplates {
id := strconv.FormatUint(*template.Id, 10)
templatesList = append(templatesList, &clients.LaunchTemplate{ID: id, Name: template.GetName()})
}
}
var lst []*computepb.InstanceTemplate
it := templatesClient.List(ctx, req)
pager := iterator.NewPager(it, it.PageInfo().MaxSize, token)
nextToken, err := pager.NextPage(&lst)
if err != nil {
return nil, nil, fmt.Errorf("unable to get next page: %w", err)
}

templatesList := make([]*clients.LaunchTemplate, 0, len(lst))
for _, template := range lst {
id := strconv.FormatUint(*template.Id, 10)
templatesList = append(templatesList, &clients.LaunchTemplate{ID: id, Name: template.GetName()})
}

return templatesList, nil
return templatesList, &nextToken, nil
}

func (c *gcpClient) InsertInstances(ctx context.Context, params *clients.GCPInstanceParams, amount int64) ([]*string, *string, error) {
Expand Down
7 changes: 4 additions & 3 deletions internal/clients/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ type EC2 interface {
// ListInstanceTypesWithPaginator lists all instance types.
ListInstanceTypes(ctx context.Context) ([]*InstanceType, error)

// ListLaunchTemplates lists all launch templates.
ListLaunchTemplates(ctx context.Context) ([]*LaunchTemplate, error)
// ListLaunchTemplates lists all launch templates return the next page token.
ListLaunchTemplates(ctx context.Context) ([]*LaunchTemplate, *string, error)

// RunInstances launches one or more instances.
//
Expand Down Expand Up @@ -156,5 +156,6 @@ type GCP interface {

GetInstanceDescriptionByID(ctx context.Context, id, zone string) (*InstanceDescription, error)

ListLaunchTemplates(ctx context.Context) ([]*LaunchTemplate, error)
// ListLaunchTemplates lists all launch templates and return the next page token.
ListLaunchTemplates(ctx context.Context) ([]*LaunchTemplate, *string, error)
}
4 changes: 2 additions & 2 deletions internal/clients/stubs/ec2_stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (mock *EC2ClientStub) ListInstanceTypes(ctx context.Context) ([]*clients.In
}, nil
}

func (mock *EC2ClientStub) ListLaunchTemplates(ctx context.Context) ([]*clients.LaunchTemplate, error) {
func (mock *EC2ClientStub) ListLaunchTemplates(ctx context.Context) ([]*clients.LaunchTemplate, *string, error) {
return []*clients.LaunchTemplate{
{
ID: "lt-8732678436272377",
Expand All @@ -152,7 +152,7 @@ func (mock *EC2ClientStub) ListLaunchTemplates(ctx context.Context) ([]*clients.
ID: "lt-8732678438462378",
Name: "XXLarge AMD64 database",
},
}, nil
}, nil, nil
}

func (mock *EC2ClientStub) CheckPermission(ctx context.Context, auth *clients.Authentication) ([]string, error) {
Expand Down
4 changes: 2 additions & 2 deletions internal/clients/stubs/gcp_stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ func (mock *GCPClientStub) GetInstanceDescriptionByID(ctx context.Context, id, z
return nil, MissingInstanceIDErr
}

func (mock *GCPClientStub) ListLaunchTemplates(ctx context.Context) ([]*clients.LaunchTemplate, error) {
return nil, nil
func (mock *GCPClientStub) ListLaunchTemplates(ctx context.Context) ([]*clients.LaunchTemplate, *string, error) {
return nil, nil, nil
}

func (mock *GCPClientStub) InsertInstances(ctx context.Context, params *clients.GCPInstanceParams, amount int64) ([]*string, *string, error) {
Expand Down
3 changes: 3 additions & 0 deletions internal/middleware/pagination_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ func Pagination(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
offset := r.URL.Query().Get("offset")
limit := r.URL.Query().Get("limit")
token := r.URL.Query().Get("token")

newCtx := page.WithOffset(r.Context(), offset)
newCtx = page.WithLimit(newCtx, limit)
newCtx = page.WithToken(newCtx, token)

next.ServeHTTP(w, r.WithContext(newCtx))
})
}
Loading

0 comments on commit ce06412

Please sign in to comment.