From 09f2968d1836c2e795419c1bfe51e8d223384e71 Mon Sep 17 00:00:00 2001 From: Luke Hoban Date: Sun, 4 Jun 2017 21:34:51 -0700 Subject: [PATCH] Decouple Deployment from Stage in aws.apigateway The raw AWS API and CloudFormation projection allow a stage to be created as part of creating a deployment. This leads to difficulties tracking the ownership of this extra stage, since it is neither created and owned seperately, nor is it discoverable after the fact from the deployment. We can keep the API simpler by not projecting this feature of the AWS API into the Lumi resource. The stage will have to be created seperately in Lumi, and it's lifecycle is well understood as a separate Lumi resource. Fixes #202. --- lib/aws/idl/apigateway/deployment.go | 48 +---------------------- lib/aws/pack/apigateway/deployment.ts | 30 +------------- lib/aws/pack/serverless/api.ts | 1 + lib/aws/provider/apigateway/deployment.go | 31 +-------------- lib/aws/rpc/apigateway/deployment.go | 47 ++-------------------- 5 files changed, 9 insertions(+), 148 deletions(-) diff --git a/lib/aws/idl/apigateway/deployment.go b/lib/aws/idl/apigateway/deployment.go index 812cf3faa..c43ddfdf1 100644 --- a/lib/aws/idl/apigateway/deployment.go +++ b/lib/aws/idl/apigateway/deployment.go @@ -24,58 +24,12 @@ import ( type Deployment struct { idl.NamedResource // restAPI is the RestAPI resource to deploy. - RestAPI *RestAPI `lumi:"restAPI"` + RestAPI *RestAPI `lumi:"restAPI,replaces"` // description is a description of the purpose of the API Gateway deployment. Description *string `lumi:"description,optional"` - // stageDescription configures the stage that API Gateway creates with this deployment. - StageDescription *StageDescription `lumi:"stageDescription,optional"` - // stageName is a name for the stage that API Gateway creates with this deployment. Use only alphanumeric - // characters. - StageName *string `lumi:"stageName,optional"` // The identifier for the deployment resource. ID string `lumi:"id,out"` // The date and time that the deployment resource was created. CreatedDate string `lumi:"createdDate,out"` } - -type StageDescription struct { - // Indicates whether cache clustering is enabled for the stage. - CacheClusterEnabled *bool `lumi:"cacheClusterEnabled,optional"` - // The size of the stage's cache cluster. - CacheClusterSize *string `lumi:"cacheClusterSize,optional"` - // Indicates whether the cached responses are encrypted. - CacheDataEncrypted *bool `lumi:"cacheDataEncrypted,optional"` - // The time-to-live (TTL) period, in seconds, that specifies how long API Gateway caches responses. - CacheTTLInSeconds *float64 `lumi:"cacheTTLInSeconds,optional"` - // Indicates whether responses are cached and returned for requests. You must enable a cache cluster on the stage - // to cache responses. For more information, see - // http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-caching.html. - CachingEnabled *bool `lumi:"cachingEnabled,optional"` - // The client certificate that API Gateway uses to call your integration endpoints in the stage. - ClientCertificate *ClientCertificate `lumi:"clientCertificate,optional"` - // Indicates whether data trace logging is enabled for methods in the stage. API Gateway pushes these logs to Amazon - // CloudWatch Logs. - DataTraceEnabled *bool `lumi:"dataTraceEnabled,optional"` - // A description of the purpose of the stage. - Description *string `lumi:"description,optional"` - // The logging level for this method. - LoggingLevel *LoggingLevel `lumi:"loggingLevel,optional"` - // Configures settings for all of the stage's methods. - MethodSettings *[]MethodSetting `lumi:"methodSettings,optional"` - // Indicates whether Amazon CloudWatch metrics are enabled for methods in the stage. - MetricsEnabled *bool `lumi:"metricsEnabled,optional"` - // The name of the stage, which API Gateway uses as the first path segment in the invoke URI. - StageName *string `lumi:"stageName,optional"` - // The number of burst requests per second that API Gateway permits across all APIs, stages, and methods in your - // AWS account. For more information, see - // http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html. - ThrottlingBurstLimit *float64 `lumi:"throttlingBurstLimit,optional"` - // The number of steady-state requests per second that API Gateway permits across all APIs, stages, and methods in - // your AWS account. For more information, see - // http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-throttling.html. - ThrottlingRateLimit *float64 `lumi:"throttlingRateLimit,optional"` - // A map that defines the stage variables. Variable names must consist of alphanumeric characters, and the values - // must match the following regular expression: `[A-Za-z0-9-._~:/?#&=,]+`. - Variables *map[string]string `lumi:"variables,optional"` -} diff --git a/lib/aws/pack/apigateway/deployment.ts b/lib/aws/pack/apigateway/deployment.ts index 96bd4e678..301f5a20b 100644 --- a/lib/aws/pack/apigateway/deployment.ts +++ b/lib/aws/pack/apigateway/deployment.ts @@ -3,16 +3,12 @@ import * as lumi from "@lumi/lumi"; -import {ClientCertificate} from "./clientCertificate"; -import {LoggingLevel, MethodSetting} from "./method"; import {RestAPI} from "./restAPI"; export class Deployment extends lumi.Resource implements DeploymentArgs { public readonly name: string; - public restAPI: RestAPI; + public readonly restAPI: RestAPI; public description?: string; - public stageDescription?: StageDescription; - public stageName?: string; public id: string; public createdDate: string; @@ -27,34 +23,12 @@ export class Deployment extends lumi.Resource implements DeploymentArgs { } this.restAPI = args.restAPI; this.description = args.description; - this.stageDescription = args.stageDescription; - this.stageName = args.stageName; } } export interface DeploymentArgs { - restAPI: RestAPI; + readonly restAPI: RestAPI; description?: string; - stageDescription?: StageDescription; - stageName?: string; -} - -export interface StageDescription { - cacheClusterEnabled?: boolean; - cacheClusterSize?: string; - cacheDataEncrypted?: boolean; - cacheTTLInSeconds?: number; - cachingEnabled?: boolean; - clientCertificate?: ClientCertificate; - dataTraceEnabled?: boolean; - description?: string; - loggingLevel?: LoggingLevel; - methodSettings?: MethodSetting[]; - metricsEnabled?: boolean; - stageName?: string; - throttlingBurstLimit?: number; - throttlingRateLimit?: number; - variables?: {[key: string]: string}; } diff --git a/lib/aws/pack/serverless/api.ts b/lib/aws/pack/serverless/api.ts index f184b722c..52ce98c29 100644 --- a/lib/aws/pack/serverless/api.ts +++ b/lib/aws/pack/serverless/api.ts @@ -97,6 +97,7 @@ export class API { } // TODO[pulumi/lumi#90]: Once we suport output properties, we can use `lambda.lambda.arn` as input // to constructing this apigateway lambda invocation uri. + // this.swaggerSpec.paths[path][swaggerMethod] = createPathSpec(lambda.lambda.arn); this.swaggerSpec.paths[path][swaggerMethod] = createPathSpec("arn:aws:lambda:us-east-1:490047557317:function:webapi-test-func"); } diff --git a/lib/aws/provider/apigateway/deployment.go b/lib/aws/provider/apigateway/deployment.go index 77a208e4f..95dee3b8e 100644 --- a/lib/aws/provider/apigateway/deployment.go +++ b/lib/aws/provider/apigateway/deployment.go @@ -3,7 +3,6 @@ package apigateway import ( - "crypto/sha1" "fmt" "strings" @@ -64,13 +63,6 @@ func (p *deploymentProvider) Check(ctx context.Context, obj *apigateway.Deployme // Create allocates a new instance of the provided resource and returns its unique ID afterwards. (The input ID // must be blank.) If this call fails, the resource must not have been created (i.e., it is "transacational"). func (p *deploymentProvider) Create(ctx context.Context, obj *apigateway.Deployment) (resource.ID, error) { - // If an explicit name is given, use it. Otherwise, auto-generate a name in part based on the resource name. - var stageName string - if obj.StageName != nil { - stageName = *obj.StageName - } else { - stageName = resource.NewUniqueHex(*obj.Name+"_", maxDeploymentName, sha1.Size) - } restAPIID, err := ParseRestAPIID(obj.RestAPI) if err != nil { return "", err @@ -79,7 +71,6 @@ func (p *deploymentProvider) Create(ctx context.Context, obj *apigateway.Deploym create := &awsapigateway.CreateDeploymentInput{ RestApiId: aws.String(restAPIID), Description: obj.Description, - StageName: aws.String(stageName), } deployment, err := p.ctx.APIGateway().CreateDeployment(create) if err != nil { @@ -107,8 +98,8 @@ func (p *deploymentProvider) Get(ctx context.Context, id resource.ID) (*apigatew } return &apigateway.Deployment{ RestAPI: NewRestAPIID(p.ctx.Region(), restAPIID), - ID: aws.StringValue(resp.Id), Description: resp.Description, + ID: aws.StringValue(resp.Id), CreatedDate: resp.CreatedDate.String(), }, nil } @@ -123,7 +114,7 @@ func (p *deploymentProvider) InspectChange(ctx context.Context, id resource.ID, // to new values. The resource ID is returned and may be different if the resource had to be recreated. func (p *deploymentProvider) Update(ctx context.Context, id resource.ID, old *apigateway.Deployment, new *apigateway.Deployment, diff *resource.ObjectDiff) error { - ops, err := patchOperations(diff, apigateway.Deployment_StageName) + ops, err := patchOperations(diff) if err != nil { return err } @@ -152,24 +143,6 @@ func (p *deploymentProvider) Delete(ctx context.Context, id resource.ID) error { if err != nil { return err } - resp, err := p.ctx.APIGateway().GetStages(&awsapigateway.GetStagesInput{ - RestApiId: aws.String(restAPIID), - DeploymentId: aws.String(deploymentID), - }) - if err != nil || resp == nil { - return err - } - if len(resp.Item) == 1 { - // Assume that the single stage associated with this deployment - // is the stage that was automatically created along with the deployment. - _, err := p.ctx.APIGateway().DeleteStage(&awsapigateway.DeleteStageInput{ - RestApiId: aws.String(restAPIID), - StageName: resp.Item[0].StageName, - }) - if err != nil { - return err - } - } _, err = p.ctx.APIGateway().DeleteDeployment(&awsapigateway.DeleteDeploymentInput{ RestApiId: aws.String(restAPIID), DeploymentId: aws.String(deploymentID), diff --git a/lib/aws/rpc/apigateway/deployment.go b/lib/aws/rpc/apigateway/deployment.go index e6806dedb..70f2a1a6e 100644 --- a/lib/aws/rpc/apigateway/deployment.go +++ b/lib/aws/rpc/apigateway/deployment.go @@ -123,6 +123,9 @@ func (p *DeploymentProvider) InspectChange( if diff.Changed("name") { replaces = append(replaces, "name") } + if diff.Changed("restAPI") { + replaces = append(replaces, "restAPI") + } } more, err := p.ops.InspectChange(ctx, id, old, new, diff) if err != nil { @@ -177,8 +180,6 @@ type Deployment struct { Name *string `json:"name,omitempty"` RestAPI resource.ID `json:"restAPI"` Description *string `json:"description,omitempty"` - StageDescription *StageDescription `json:"stageDescription,omitempty"` - StageName *string `json:"stageName,omitempty"` ID string `json:"id,omitempty"` CreatedDate string `json:"createdDate,omitempty"` } @@ -188,50 +189,8 @@ const ( Deployment_Name = "name" Deployment_RestAPI = "restAPI" Deployment_Description = "description" - Deployment_StageDescription = "stageDescription" - Deployment_StageName = "stageName" Deployment_ID = "id" Deployment_CreatedDate = "createdDate" ) -/* Marshalable StageDescription structure(s) */ - -// StageDescription is a marshalable representation of its corresponding IDL type. -type StageDescription struct { - CacheClusterEnabled *bool `json:"cacheClusterEnabled,omitempty"` - CacheClusterSize *string `json:"cacheClusterSize,omitempty"` - CacheDataEncrypted *bool `json:"cacheDataEncrypted,omitempty"` - CacheTTLInSeconds *float64 `json:"cacheTTLInSeconds,omitempty"` - CachingEnabled *bool `json:"cachingEnabled,omitempty"` - ClientCertificate *resource.ID `json:"clientCertificate,omitempty"` - DataTraceEnabled *bool `json:"dataTraceEnabled,omitempty"` - Description *string `json:"description,omitempty"` - LoggingLevel *LoggingLevel `json:"loggingLevel,omitempty"` - MethodSettings *[]MethodSetting `json:"methodSettings,omitempty"` - MetricsEnabled *bool `json:"metricsEnabled,omitempty"` - StageName *string `json:"stageName,omitempty"` - ThrottlingBurstLimit *float64 `json:"throttlingBurstLimit,omitempty"` - ThrottlingRateLimit *float64 `json:"throttlingRateLimit,omitempty"` - Variables *map[string]string `json:"variables,omitempty"` -} - -// StageDescription's properties have constants to make dealing with diffs and property bags easier. -const ( - StageDescription_CacheClusterEnabled = "cacheClusterEnabled" - StageDescription_CacheClusterSize = "cacheClusterSize" - StageDescription_CacheDataEncrypted = "cacheDataEncrypted" - StageDescription_CacheTTLInSeconds = "cacheTTLInSeconds" - StageDescription_CachingEnabled = "cachingEnabled" - StageDescription_ClientCertificate = "clientCertificate" - StageDescription_DataTraceEnabled = "dataTraceEnabled" - StageDescription_Description = "description" - StageDescription_LoggingLevel = "loggingLevel" - StageDescription_MethodSettings = "methodSettings" - StageDescription_MetricsEnabled = "metricsEnabled" - StageDescription_StageName = "stageName" - StageDescription_ThrottlingBurstLimit = "throttlingBurstLimit" - StageDescription_ThrottlingRateLimit = "throttlingRateLimit" - StageDescription_Variables = "variables" -) -