package awsm-codegen

  1. Overview
  2. Docs
AWS botocore code generator

Install

dune-project
 Dependency

Authors

Maintainers

Sources

0.1.0.tar.gz
md5=db5777910e155df33255f50c50daa046
sha512=18775715f99f5ba56c6dee40d7b4c4ab7f5d583327d2cc5c50d0cdae4c76c7b510e0ff974577cc0a9d82f497b979daf8af14f9e5741e9fbc5c83aa5928039c6b

doc/src/awsm-codegen/botocore_endpoints.ml.html

Source file botocore_endpoints.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
open! Core
open! Import

(* Warning 30 complains if we have 'defaults' in multiple fields. *)
[@@@warning "-30"]

type credentialScope =
  { region : Region.t option
  ; service : string option
  }
[@@deriving sexp]

type uri_token =
  [ `String_token of string
  | `Service_token
  | `Region_token
  | `DnsSuffix_token
  ]
[@@deriving sexp]

type uri_pattern = uri_token list [@@deriving sexp]

type variant =
  { dnsSuffix : string option
  ; hostname : uri_pattern option
  ; tags : string list
  }
[@@deriving sexp]

type properties =
  { credentialScope : credentialScope option
  ; hostname : uri_pattern option
  ; protocols : string list option
  ; sslCommonName : string option
  ; signatureVersions : [ `v2 | `v3 | `v4 | `s3 | `s3v4 ] list option
  ; variants : variant list option
  ; deprecated : bool option
  }
[@@deriving sexp]

type service =
  { defaults : properties option
  ; endpoints : (string * properties) list
  ; isRegionalized : bool option
  ; partitionEndpoint : string option
  }
[@@deriving sexp]

type region = { description : string } [@@deriving sexp]

type partition =
  { defaults : properties option
  ; dnsSuffix : string
  ; partition : string
  ; partitionName : string
  ; regionRegex : string
  ; regions : (string * region) list
  ; services : (string * service) list
  }
[@@deriving sexp]

type t =
  { partitions : partition list
  ; version : int
  }
[@@deriving sexp]

module Json0 = struct
  let uri_token buf : (uri_token option, [ `Invalid ]) result =
    match%sedlex buf with
    | "{dnsSuffix}" -> Ok (Some `DnsSuffix_token)
    | "{service}" -> Ok (Some `Service_token)
    | "{region}" -> Ok (Some `Region_token)
    | eof -> Ok None
    | Plus (Compl (Chars "{}")) -> Ok (Some (`String_token (Sedlexing.Latin1.lexeme buf)))
    | _ -> Error `Invalid
  ;;

  let parse_uri s =
    match Util.tokenize uri_token s with
    | Ok _ as x -> x
    | Error `Invalid -> Result.failf "Invalid uri: %s" s
  ;;

  (*
let constraint_ =
  Json_parser.parse_with (function
      | `List [ `String "region"; `String op; values ] ->
        let open Result.Let_syntax in
        let%bind op = parse_op op in
        let%bind values = parse_constraint_value values in
        let%map test =
          match op, values with
          | `equals, [ x ] -> Ok (`equals x)
          | `notEquals, [ x ] -> Ok (`notEquals x)
          | `startsWith, [ x ] -> Ok (`startsWith x)
          | `notStartsWith, [ x ] -> Ok (`notStartsWith x)
          | `oneOf, vals -> Ok (`oneOf vals)
          | _ -> Error "Malformed constraint"
        in
        Constraint (`Region, test)
      | `List _ -> Error "Expected array of size 3 starting with 'region' for constraint"
      | _ -> Error "Expected array for constraint")
;;
*)
  let parse_signatureVersion = function
    | "v2" -> Ok `v2
    | "v3" -> Ok `v3
    | "v4" -> Ok `v4
    | "s3" -> Ok `s3
    | "s3v4" -> Ok `s3v4
    | s -> Result.failf "Unknown signatureVersion %s" s
  ;;

  let credential_scope =
    let open Json_parser in
    record
      (let%map region = field_opt "region" (string >>| Region.of_string)
       and service = field_opt "service" string in
       { region; service })
  ;;

  let variant =
    let open Json_parser in
    record
      (let%map dnsSuffix = field_opt "dnsSuffix" string
       and hostname = field_opt "hostname" (map_result string ~f:parse_uri)
       and tags = field "tags" (list string) in
       { dnsSuffix; hostname; tags })
  ;;

  let properties =
    let open Json_parser in
    record
      (let%map signatureVersions =
         field_opt
           "signatureVersions"
           (list (map_result string ~f:parse_signatureVersion))
       and credentialScope = field_opt "credentialScope" credential_scope
       and hostname = field_opt "hostname" (map_result string ~f:parse_uri)
       and protocols = field_opt "protocols" (list string)
       and sslCommonName = field_opt "sslCommonName" string
       and variants = field_opt "variants" (list variant)
       and deprecated = field_opt "deprecated" bool in
       { credentialScope
       ; hostname
       ; protocols
       ; sslCommonName
       ; signatureVersions
       ; variants
       ; deprecated
       })
  ;;

  let region =
    let open Json_parser in
    record
      (let%map description = field "description" string in
       { description })
  ;;

  let endpoint_service =
    let open Json_parser in
    record
      (let%map defaults = field_opt "defaults" properties
       and endpoints = field "endpoints" (dict properties)
       and isRegionalized = field_opt "isRegionalized" bool
       and partitionEndpoint = field_opt "partitionEndpoint" string in
       { defaults; endpoints; isRegionalized; partitionEndpoint })
  ;;

  let partition =
    let open Json_parser in
    record
      (let%map defaults = field_opt "defaults" properties
       and dnsSuffix = field "dnsSuffix" string
       and partition = field "partition" string
       and partitionName = field "partitionName" string
       and regionRegex = field "regionRegex" string
       and regions = field "regions" (dict region)
       and services = field "services" (dict endpoint_service) in
       { defaults; dnsSuffix; partition; partitionName; regionRegex; regions; services })
  ;;
end

let of_json x =
  let t =
    x
    |> Json.from_string
    |> Json_parser.run_exn
         (let open Json_parser in
         record
           (let%map partitions = field "partitions" (list Json0.partition)
            and version = field "version" int in
            { partitions; version }))
  in
  let () =
    match t.version with
    | 3 -> ()
    | _ -> failwithf "unexpected version: %d" t.version ()
  in
  t
;;

module Endpoint_rules_for_precompute = struct
  module Botodata = Botodata

  let str_regexp = Memo.general Re.Perl.compile_pat

  let lookup_partition =
    Memo.general (fun (ep, region) ->
      let region_s = Region.to_string region in
      match
        List.find ep.partitions ~f:(fun partition ->
          let rex = str_regexp partition.regionRegex in
          Option.is_some (Re.exec_opt rex region_s))
      with
      | None -> failwithf !"no partition found for region: %{Region}" region ()
      | Some partition -> partition)
  ;;

  let lookup_service_properties_memo =
    Memo.general (fun (region, service, (partition : partition)) ->
      let region_s = Region.to_string region in
      let service_s = Service.to_string service in
      let service_s =
        (* FIXME: need to do more sophisticated Endpoint_rules processing.
       This is a temporary shim to get a critical service running. *)
        match service_s with
        | "sso" -> "portal.sso"
        | s -> s
      in
      match
        List.find partition.services ~f:(fun (service_name, _service_spec) ->
          String.( = ) service_name service_s)
      with
      | None -> None, None
      | Some (_service_name, service_spec) -> (
        let service_defaults = service_spec.defaults in
        let match_endpoint =
          match service_spec.isRegionalized with
          | None | Some false -> "aws-global"
          | Some true -> region_s
        in
        match
          List.find service_spec.endpoints ~f:(fun (endpoint, _properties) ->
            String.( = ) match_endpoint endpoint)
        with
        | None -> service_defaults, None
        | Some (_endpoint, properties) -> service_defaults, Some properties))
  ;;

  let lookup_service_properties ~region ~service ~partition =
    lookup_service_properties_memo (region, service, partition)
  ;;

  let lookup_credential_scope ep ~region:orig_region service =
    let partition = lookup_partition (ep, orig_region) in
    let credential_scope =
      match lookup_service_properties ~partition ~service ~region:orig_region with
      | _, None -> None
      | _, Some properties -> properties.credentialScope
    in
    (match credential_scope with
     | None -> orig_region
     | Some { region = None; service = _ } -> orig_region
     | Some { region = Some region; service = _ } -> region)
    |> Region.to_string
  ;;

  let lookup_uri ep ~scheme ~region ~service =
    let service_s = Service.to_string service in
    let service_s =
      (* FIXME: need to do more sophisticated Endpoint_rules processing.
       This is a temporary shim to get a critical service running. *)
      match service_s with
      | "sso" -> "portal.sso"
      | s -> s
    in
    let partition = lookup_partition (ep, region) in
    let partition_hostname =
      let partition_defaults =
        Option.value_exn
          partition.defaults
          ~message:(sprintf "no defaults for %s" partition.partitionName)
      in
      match partition_defaults.hostname with
      | None | Some [] ->
        failwithf "no default hostname schema for partition %s" partition.partitionName ()
      | Some hostname -> Some hostname
    in
    let service_hostname =
      match lookup_service_properties ~partition ~service ~region with
      | Some service_defaults, None -> service_defaults.hostname
      | Some _, Some { hostname = Some hostname; _ } -> Some hostname
      | Some service_defaults, Some { hostname = None; _ } -> service_defaults.hostname
      | None, Some { hostname = Some hostname; _ } -> Some hostname
      | None, Some { hostname = None; _ } -> None
      | None, None -> None
    in
    let scheme =
      match scheme with
      | `HTTP -> "http"
      | `HTTPS -> "https"
    in
    let hostname =
      match service_hostname, partition_hostname with
      | Some h, _ -> h
      | None, Some h -> h
      | _, None -> assert false
    in
    let host =
      List.map hostname ~f:(function
        | `String_token s -> s
        | `Service_token -> service_s
        | `Region_token -> Region.to_string region
        | `DnsSuffix_token -> partition.dnsSuffix)
    in
    String.concat (scheme :: "://" :: host) ~sep:""
  ;;
end

let gen_catch_all expr = Ast_helper.Exp.case Ast_convenience.(pvar "_unknown") expr

let make_lookup_uri ep =
  let loc = !Ast_helper.default_loc in
  let uri_rules =
    List.concat_map [ `HTTP; `HTTPS ] ~f:(fun scheme ->
      List.concat_map Region.all ~f:(fun region ->
        List.concat_map Service.all ~f:(fun service ->
          let uri =
            Endpoint_rules_for_precompute.lookup_uri ep ~scheme ~region ~service
          in
          [ scheme, region, service, uri ])))
  in
  let uri_cases =
    List.map uri_rules ~f:(fun (scheme, region, service, uri) ->
      let scheme_pvar =
        match scheme with
        | `HTTP -> "`HTTP"
        | `HTTPS -> "`HTTPS"
      in
      let region_s = Region.to_string region in
      let service_s = Service.to_string service in
      Ast_helper.Exp.case
        Ast_convenience.(ptuple [ pvar scheme_pvar; pstr region_s; pstr service_s ])
        (Ast_convenience.str uri))
    @ [ gen_catch_all
          [%expr
            failwithf
              "unknown endpoint for %s %s, %s"
              (match scheme with
               | `HTTPS -> "https"
               | `HTTP -> "http")
              region
              service
              ()]
      ]
  in
  let uri_match_with = Ast_helper.Exp.match_ [%expr scheme, region, service] uri_cases in
  [%stri
    let lookup_uri ~region service scheme =
      let region = Region.to_string region in
      let service = Service.to_string service in
      let uri_s = [%e uri_match_with] in
      Uri.of_string uri_s
    ;;]
;;

let make_lookup_credential_scope ep =
  let loc = !Ast_helper.default_loc in
  let credential_scope_rules =
    List.concat_map Region.all ~f:(fun region ->
      List.concat_map Service.all ~f:(fun service ->
        let credential_scope =
          Endpoint_rules_for_precompute.lookup_credential_scope ep ~region service
        in
        [ region, service, credential_scope ]))
  in
  let credential_scope_cases =
    List.map credential_scope_rules ~f:(fun (region, service, credential_scope) ->
      let region_s = Region.to_string region in
      let service_s = Service.to_string service in
      Ast_helper.Exp.case
        Ast_convenience.(ptuple [ pstr region_s; pstr service_s ])
        (Ast_convenience.str credential_scope))
    @ [ gen_catch_all
          [%expr failwithf "unknown credential scope for %s, %s" region service ()]
      ]
  in
  let credential_scope_match_with =
    Ast_helper.Exp.match_ [%expr region, service] credential_scope_cases
  in
  [%stri
    let lookup_credential_scope ~region service =
      let region = Region.to_string region in
      let service = Service.to_string service in
      let credential_scope_s = [%e credential_scope_match_with] in
      Region.of_string credential_scope_s
    ;;]
;;