customization_passes.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // +build codegen
  2. package api
  3. import (
  4. "io/ioutil"
  5. "path/filepath"
  6. "strings"
  7. )
  8. type service struct {
  9. srcName string
  10. dstName string
  11. serviceVersion string
  12. }
  13. var mergeServices = map[string]service{
  14. "dynamodbstreams": service{
  15. dstName: "dynamodb",
  16. srcName: "streams.dynamodb",
  17. },
  18. "wafregional": service{
  19. dstName: "waf",
  20. srcName: "waf-regional",
  21. serviceVersion: "2015-08-24",
  22. },
  23. }
  24. // customizationPasses Executes customization logic for the API by package name.
  25. func (a *API) customizationPasses() {
  26. var svcCustomizations = map[string]func(*API){
  27. "s3": s3Customizations,
  28. "cloudfront": cloudfrontCustomizations,
  29. "rds": rdsCustomizations,
  30. // Disable endpoint resolving for services that require customer
  31. // to provide endpoint them selves.
  32. "cloudsearchdomain": disableEndpointResolving,
  33. "iotdataplane": disableEndpointResolving,
  34. }
  35. for k, _ := range mergeServices {
  36. svcCustomizations[k] = mergeServicesCustomizations
  37. }
  38. if fn := svcCustomizations[a.PackageName()]; fn != nil {
  39. fn(a)
  40. }
  41. }
  42. // s3Customizations customizes the API generation to replace values specific to S3.
  43. func s3Customizations(a *API) {
  44. var strExpires *Shape
  45. for name, s := range a.Shapes {
  46. // Remove ContentMD5 members
  47. if _, ok := s.MemberRefs["ContentMD5"]; ok {
  48. delete(s.MemberRefs, "ContentMD5")
  49. }
  50. for _, refName := range []string{"Bucket", "SSECustomerKey", "CopySourceSSECustomerKey"} {
  51. if ref, ok := s.MemberRefs[refName]; ok {
  52. ref.GenerateGetter = true
  53. }
  54. }
  55. // Expires should be a string not time.Time since the format is not
  56. // enforced by S3, and any value can be set to this field outside of the SDK.
  57. if strings.HasSuffix(name, "Output") {
  58. if ref, ok := s.MemberRefs["Expires"]; ok {
  59. if strExpires == nil {
  60. newShape := *ref.Shape
  61. strExpires = &newShape
  62. strExpires.Type = "string"
  63. strExpires.refs = []*ShapeRef{}
  64. }
  65. ref.Shape.removeRef(ref)
  66. ref.Shape = strExpires
  67. ref.Shape.refs = append(ref.Shape.refs, &s.MemberRef)
  68. }
  69. }
  70. }
  71. s3CustRemoveHeadObjectModeledErrors(a)
  72. }
  73. // S3 HeadObject API call incorrect models NoSuchKey as valid
  74. // error code that can be returned. This operation does not
  75. // return error codes, all error codes are derived from HTTP
  76. // status codes.
  77. //
  78. // aws/aws-sdk-go#1208
  79. func s3CustRemoveHeadObjectModeledErrors(a *API) {
  80. op, ok := a.Operations["HeadObject"]
  81. if !ok {
  82. return
  83. }
  84. op.Documentation += `
  85. //
  86. // See http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html#RESTErrorResponses
  87. // for more information on returned errors.`
  88. op.ErrorRefs = []ShapeRef{}
  89. }
  90. // cloudfrontCustomizations customized the API generation to replace values
  91. // specific to CloudFront.
  92. func cloudfrontCustomizations(a *API) {
  93. // MaxItems members should always be integers
  94. for _, s := range a.Shapes {
  95. if ref, ok := s.MemberRefs["MaxItems"]; ok {
  96. ref.ShapeName = "Integer"
  97. ref.Shape = a.Shapes["Integer"]
  98. }
  99. }
  100. }
  101. // mergeServicesCustomizations references any duplicate shapes from DynamoDB
  102. func mergeServicesCustomizations(a *API) {
  103. info := mergeServices[a.PackageName()]
  104. p := strings.Replace(a.path, info.srcName, info.dstName, -1)
  105. if info.serviceVersion != "" {
  106. index := strings.LastIndex(p, "/")
  107. files, _ := ioutil.ReadDir(p[:index])
  108. if len(files) > 1 {
  109. panic("New version was introduced")
  110. }
  111. p = p[:index] + "/" + info.serviceVersion
  112. }
  113. file := filepath.Join(p, "api-2.json")
  114. serviceAPI := API{}
  115. serviceAPI.Attach(file)
  116. serviceAPI.Setup()
  117. for n := range a.Shapes {
  118. if _, ok := serviceAPI.Shapes[n]; ok {
  119. a.Shapes[n].resolvePkg = "github.com/aws/aws-sdk-go/service/" + info.dstName
  120. }
  121. }
  122. }
  123. // rdsCustomizations are customization for the service/rds. This adds non-modeled fields used for presigning.
  124. func rdsCustomizations(a *API) {
  125. inputs := []string{
  126. "CopyDBSnapshotInput",
  127. "CreateDBInstanceReadReplicaInput",
  128. "CopyDBClusterSnapshotInput",
  129. "CreateDBClusterInput",
  130. }
  131. for _, input := range inputs {
  132. if ref, ok := a.Shapes[input]; ok {
  133. ref.MemberRefs["SourceRegion"] = &ShapeRef{
  134. Documentation: docstring(`SourceRegion is the source region where the resource exists. This is not sent over the wire and is only used for presigning. This value should always have the same region as the source ARN.`),
  135. ShapeName: "String",
  136. Shape: a.Shapes["String"],
  137. Ignore: true,
  138. }
  139. ref.MemberRefs["DestinationRegion"] = &ShapeRef{
  140. Documentation: docstring(`DestinationRegion is used for presigning the request to a given region.`),
  141. ShapeName: "String",
  142. Shape: a.Shapes["String"],
  143. }
  144. }
  145. }
  146. }
  147. func disableEndpointResolving(a *API) {
  148. a.Metadata.NoResolveEndpoint = true
  149. }