/vendor/github.com/aws/aws-sdk-go/aws/endpoints/endpoints.go

https://gitlab.com/jimakker/rancher-letsencrypt · Go · 397 lines · 194 code · 54 blank · 149 comment · 10 complexity · be03904e9dc7b008fd37091662ef4328 MD5 · raw file

  1. package endpoints
  2. import (
  3. "fmt"
  4. "regexp"
  5. "github.com/aws/aws-sdk-go/aws/awserr"
  6. )
  7. // Options provide the configuration needed to direct how the
  8. // endpoints will be resolved.
  9. type Options struct {
  10. // DisableSSL forces the endpoint to be resolved as HTTP.
  11. // instead of HTTPS if the service supports it.
  12. DisableSSL bool
  13. // Sets the resolver to resolve the endpoint as a dualstack endpoint
  14. // for the service. If dualstack support for a service is not known and
  15. // StrictMatching is not enabled a dualstack endpoint for the service will
  16. // be returned. This endpoint may not be valid. If StrictMatching is
  17. // enabled only services that are known to support dualstack will return
  18. // dualstack endpoints.
  19. UseDualStack bool
  20. // Enables strict matching of services and regions resolved endpoints.
  21. // If the partition doesn't enumerate the exact service and region an
  22. // error will be returned. This option will prevent returning endpoints
  23. // that look valid, but may not resolve to any real endpoint.
  24. StrictMatching bool
  25. // Enables resolving a service endpoint based on the region provided if the
  26. // service does not exist. The service endpoint ID will be used as the service
  27. // domain name prefix. By default the endpoint resolver requires the service
  28. // to be known when resolving endpoints.
  29. //
  30. // If resolving an endpoint on the partition list the provided region will
  31. // be used to determine which partition's domain name pattern to the service
  32. // endpoint ID with. If both the service and region are unkonwn and resolving
  33. // the endpoint on partition list an UnknownEndpointError error will be returned.
  34. //
  35. // If resolving and endpoint on a partition specific resolver that partition's
  36. // domain name pattern will be used with the service endpoint ID. If both
  37. // region and service do not exist when resolving an endpoint on a specific
  38. // partition the partition's domain pattern will be used to combine the
  39. // endpoint and region together.
  40. //
  41. // This option is ignored if StrictMatching is enabled.
  42. ResolveUnknownService bool
  43. }
  44. // Set combines all of the option functions together.
  45. func (o *Options) Set(optFns ...func(*Options)) {
  46. for _, fn := range optFns {
  47. fn(o)
  48. }
  49. }
  50. // DisableSSLOption sets the DisableSSL options. Can be used as a functional
  51. // option when resolving endpoints.
  52. func DisableSSLOption(o *Options) {
  53. o.DisableSSL = true
  54. }
  55. // UseDualStackOption sets the UseDualStack option. Can be used as a functional
  56. // option when resolving endpoints.
  57. func UseDualStackOption(o *Options) {
  58. o.UseDualStack = true
  59. }
  60. // StrictMatchingOption sets the StrictMatching option. Can be used as a functional
  61. // option when resolving endpoints.
  62. func StrictMatchingOption(o *Options) {
  63. o.StrictMatching = true
  64. }
  65. // ResolveUnknownServiceOption sets the ResolveUnknownService option. Can be used
  66. // as a functional option when resolving endpoints.
  67. func ResolveUnknownServiceOption(o *Options) {
  68. o.ResolveUnknownService = true
  69. }
  70. // A Resolver provides the interface for functionality to resolve endpoints.
  71. // The build in Partition and DefaultResolver return value satisfy this interface.
  72. type Resolver interface {
  73. EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
  74. }
  75. // ResolverFunc is a helper utility that wraps a function so it satisfies the
  76. // Resolver interface. This is useful when you want to add additional endpoint
  77. // resolving logic, or stub out specific endpoints with custom values.
  78. type ResolverFunc func(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error)
  79. // EndpointFor wraps the ResolverFunc function to satisfy the Resolver interface.
  80. func (fn ResolverFunc) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
  81. return fn(service, region, opts...)
  82. }
  83. var schemeRE = regexp.MustCompile("^([^:]+)://")
  84. // AddScheme adds the HTTP or HTTPS schemes to a endpoint URL if there is no
  85. // scheme. If disableSSL is true HTTP will set HTTP instead of the default HTTPS.
  86. //
  87. // If disableSSL is set, it will only set the URL's scheme if the URL does not
  88. // contain a scheme.
  89. func AddScheme(endpoint string, disableSSL bool) string {
  90. if !schemeRE.MatchString(endpoint) {
  91. scheme := "https"
  92. if disableSSL {
  93. scheme = "http"
  94. }
  95. endpoint = fmt.Sprintf("%s://%s", scheme, endpoint)
  96. }
  97. return endpoint
  98. }
  99. // EnumPartitions a provides a way to retrieve the underlying partitions that
  100. // make up the SDK's default Resolver, or any resolver decoded from a model
  101. // file.
  102. //
  103. // Use this interface with DefaultResolver and DecodeModels to get the list of
  104. // Partitions.
  105. type EnumPartitions interface {
  106. Partitions() []Partition
  107. }
  108. // A Partition provides the ability to enumerate the partition's regions
  109. // and services.
  110. type Partition struct {
  111. id string
  112. p *partition
  113. }
  114. // ID returns the identifier of the partition.
  115. func (p *Partition) ID() string { return p.id }
  116. // EndpointFor attempts to resolve the endpoint based on service and region.
  117. // See Options for information on configuring how the endpoint is resolved.
  118. //
  119. // If the service cannot be found in the metadata the UnknownServiceError
  120. // error will be returned. This validation will occur regardless if
  121. // StrictMatching is enabled. To enable resolving unknown services set the
  122. // "ResolveUnknownService" option to true. When StrictMatching is disabled
  123. // this option allows the partition resolver to resolve a endpoint based on
  124. // the service endpoint ID provided.
  125. //
  126. // When resolving endpoints you can choose to enable StrictMatching. This will
  127. // require the provided service and region to be known by the partition.
  128. // If the endpoint cannot be strictly resolved an error will be returned. This
  129. // mode is useful to ensure the endpoint resolved is valid. Without
  130. // StrictMatching enabled the endpoint returned my look valid but may not work.
  131. // StrictMatching requires the SDK to be updated if you want to take advantage
  132. // of new regions and services expansions.
  133. //
  134. // Errors that can be returned.
  135. // * UnknownServiceError
  136. // * UnknownEndpointError
  137. func (p *Partition) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
  138. return p.p.EndpointFor(service, region, opts...)
  139. }
  140. // Regions returns a map of Regions indexed by their ID. This is useful for
  141. // enumerating over the regions in a partition.
  142. func (p *Partition) Regions() map[string]Region {
  143. rs := map[string]Region{}
  144. for id := range p.p.Regions {
  145. rs[id] = Region{
  146. id: id,
  147. p: p.p,
  148. }
  149. }
  150. return rs
  151. }
  152. // Services returns a map of Service indexed by their ID. This is useful for
  153. // enumerating over the services in a partition.
  154. func (p *Partition) Services() map[string]Service {
  155. ss := map[string]Service{}
  156. for id := range p.p.Services {
  157. ss[id] = Service{
  158. id: id,
  159. p: p.p,
  160. }
  161. }
  162. return ss
  163. }
  164. // A Region provides information about a region, and ability to resolve an
  165. // endpoint from the context of a region, given a service.
  166. type Region struct {
  167. id, desc string
  168. p *partition
  169. }
  170. // ID returns the region's identifier.
  171. func (r *Region) ID() string { return r.id }
  172. // ResolveEndpoint resolves an endpoint from the context of the region given
  173. // a service. See Partition.EndpointFor for usage and errors that can be returned.
  174. func (r *Region) ResolveEndpoint(service string, opts ...func(*Options)) (ResolvedEndpoint, error) {
  175. return r.p.EndpointFor(service, r.id, opts...)
  176. }
  177. // Services returns a list of all services that are known to be in this region.
  178. func (r *Region) Services() map[string]Service {
  179. ss := map[string]Service{}
  180. for id, s := range r.p.Services {
  181. if _, ok := s.Endpoints[r.id]; ok {
  182. ss[id] = Service{
  183. id: id,
  184. p: r.p,
  185. }
  186. }
  187. }
  188. return ss
  189. }
  190. // A Service provides information about a service, and ability to resolve an
  191. // endpoint from the context of a service, given a region.
  192. type Service struct {
  193. id string
  194. p *partition
  195. }
  196. // ID returns the identifier for the service.
  197. func (s *Service) ID() string { return s.id }
  198. // ResolveEndpoint resolves an endpoint from the context of a service given
  199. // a region. See Partition.EndpointFor for usage and errors that can be returned.
  200. func (s *Service) ResolveEndpoint(region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
  201. return s.p.EndpointFor(s.id, region, opts...)
  202. }
  203. // Endpoints returns a map of Endpoints indexed by their ID for all known
  204. // endpoints for a service.
  205. func (s *Service) Endpoints() map[string]Endpoint {
  206. es := map[string]Endpoint{}
  207. for id := range s.p.Services[s.id].Endpoints {
  208. es[id] = Endpoint{
  209. id: id,
  210. serviceID: s.id,
  211. p: s.p,
  212. }
  213. }
  214. return es
  215. }
  216. // A Endpoint provides information about endpoints, and provides the ability
  217. // to resolve that endpoint for the service, and the region the endpoint
  218. // represents.
  219. type Endpoint struct {
  220. id string
  221. serviceID string
  222. p *partition
  223. }
  224. // ID returns the identifier for an endpoint.
  225. func (e *Endpoint) ID() string { return e.id }
  226. // ServiceID returns the identifier the endpoint belongs to.
  227. func (e *Endpoint) ServiceID() string { return e.serviceID }
  228. // ResolveEndpoint resolves an endpoint from the context of a service and
  229. // region the endpoint represents. See Partition.EndpointFor for usage and
  230. // errors that can be returned.
  231. func (e *Endpoint) ResolveEndpoint(opts ...func(*Options)) (ResolvedEndpoint, error) {
  232. return e.p.EndpointFor(e.serviceID, e.id, opts...)
  233. }
  234. // A ResolvedEndpoint is an endpoint that has been resolved based on a partition
  235. // service, and region.
  236. type ResolvedEndpoint struct {
  237. // The endpoint URL
  238. URL string
  239. // The region that should be used for signing requests.
  240. SigningRegion string
  241. // The service name that should be used for signing requests.
  242. SigningName string
  243. // The signing method that should be used for signing requests.
  244. SigningMethod string
  245. }
  246. // So that the Error interface type can be included as an anonymous field
  247. // in the requestError struct and not conflict with the error.Error() method.
  248. type awsError awserr.Error
  249. // A EndpointNotFoundError is returned when in StrictMatching mode, and the
  250. // endpoint for the service and region cannot be found in any of the partitions.
  251. type EndpointNotFoundError struct {
  252. awsError
  253. Partition string
  254. Service string
  255. Region string
  256. }
  257. //// NewEndpointNotFoundError builds and returns NewEndpointNotFoundError.
  258. //func NewEndpointNotFoundError(p, s, r string) EndpointNotFoundError {
  259. // return EndpointNotFoundError{
  260. // awsError: awserr.New("EndpointNotFoundError", "unable to find endpoint", nil),
  261. // Partition: p,
  262. // Service: s,
  263. // Region: r,
  264. // }
  265. //}
  266. //
  267. //// Error returns string representation of the error.
  268. //func (e EndpointNotFoundError) Error() string {
  269. // extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
  270. // e.Partition, e.Service, e.Region)
  271. // return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
  272. //}
  273. //
  274. //// String returns the string representation of the error.
  275. //func (e EndpointNotFoundError) String() string {
  276. // return e.Error()
  277. //}
  278. // A UnknownServiceError is returned when the service does not resolve to an
  279. // endpoint. Includes a list of all known services for the partition. Returned
  280. // when a partition does not support the service.
  281. type UnknownServiceError struct {
  282. awsError
  283. Partition string
  284. Service string
  285. Known []string
  286. }
  287. // NewUnknownServiceError builds and returns UnknownServiceError.
  288. func NewUnknownServiceError(p, s string, known []string) UnknownServiceError {
  289. return UnknownServiceError{
  290. awsError: awserr.New("UnknownServiceError",
  291. "could not resolve endpoint for unknown service", nil),
  292. Partition: p,
  293. Service: s,
  294. Known: known,
  295. }
  296. }
  297. // String returns the string representation of the error.
  298. func (e UnknownServiceError) Error() string {
  299. extra := fmt.Sprintf("partition: %q, service: %q",
  300. e.Partition, e.Service)
  301. if len(e.Known) > 0 {
  302. extra += fmt.Sprintf(", known: %v", e.Known)
  303. }
  304. return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
  305. }
  306. // String returns the string representation of the error.
  307. func (e UnknownServiceError) String() string {
  308. return e.Error()
  309. }
  310. // A UnknownEndpointError is returned when in StrictMatching mode and the
  311. // service is valid, but the region does not resolve to an endpoint. Includes
  312. // a list of all known endpoints for the service.
  313. type UnknownEndpointError struct {
  314. awsError
  315. Partition string
  316. Service string
  317. Region string
  318. Known []string
  319. }
  320. // NewUnknownEndpointError builds and returns UnknownEndpointError.
  321. func NewUnknownEndpointError(p, s, r string, known []string) UnknownEndpointError {
  322. return UnknownEndpointError{
  323. awsError: awserr.New("UnknownEndpointError",
  324. "could not resolve endpoint", nil),
  325. Partition: p,
  326. Service: s,
  327. Region: r,
  328. Known: known,
  329. }
  330. }
  331. // String returns the string representation of the error.
  332. func (e UnknownEndpointError) Error() string {
  333. extra := fmt.Sprintf("partition: %q, service: %q, region: %q",
  334. e.Partition, e.Service, e.Region)
  335. if len(e.Known) > 0 {
  336. extra += fmt.Sprintf(", known: %v", e.Known)
  337. }
  338. return awserr.SprintError(e.Code(), e.Message(), extra, e.OrigErr())
  339. }
  340. // String returns the string representation of the error.
  341. func (e UnknownEndpointError) String() string {
  342. return e.Error()
  343. }