diff --git a/.changelog/26244.txt b/.changelog/26244.txt new file mode 100644 index 00000000000..c5c8751d0e1 --- /dev/null +++ b/.changelog/26244.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_comprehend_entity_recognizer +``` diff --git a/.ci/.semgrep-service-name0.yml b/.ci/.semgrep-service-name0.yml index 5c859afa1c9..350dcaee5b2 100644 --- a/.ci/.semgrep-service-name0.yml +++ b/.ci/.semgrep-service-name0.yml @@ -2896,92 +2896,105 @@ rules: patterns: - pattern-regex: "(?i)CognitoIDP" severity: WARNING - - id: configservice-in-func-name + - id: comprehend-in-func-name languages: - go - message: Do not use "ConfigService" in func name inside configservice package + message: Do not use "Comprehend" in func name inside comprehend package paths: include: - - internal/service/configservice + - internal/service/comprehend patterns: - pattern: func $NAME( ... ) { ... } - metavariable-pattern: metavariable: $NAME patterns: - - pattern-regex: "(?i)ConfigService" + - pattern-regex: "(?i)Comprehend" - pattern-not-regex: ^TestAcc.* severity: WARNING - - id: configservice-in-test-name + - id: comprehend-in-test-name languages: - go - message: Include "ConfigService" in test name + message: Include "Comprehend" in test name paths: include: - - internal/service/configservice/*_test.go + - internal/service/comprehend/*_test.go patterns: - pattern: func $NAME( ... ) { ... } - metavariable-pattern: metavariable: $NAME patterns: - - pattern-not-regex: "^TestAccConfigService" + - pattern-not-regex: "^TestAccComprehend" - pattern-regex: ^TestAcc.* severity: WARNING - - id: configservice-in-const-name + - id: comprehend-in-const-name languages: - go - message: Do not use "ConfigService" in const name inside configservice package + message: Do not use "Comprehend" in const name inside comprehend package paths: include: - - internal/service/configservice + - internal/service/comprehend patterns: - pattern: const $NAME = ... - metavariable-pattern: metavariable: $NAME patterns: - - pattern-regex: "(?i)ConfigService" + - pattern-regex: "(?i)Comprehend" severity: WARNING - - id: configservice-in-var-name + - id: comprehend-in-var-name languages: - go - message: Do not use "ConfigService" in var name inside configservice package + message: Do not use "Comprehend" in var name inside comprehend package paths: include: - - internal/service/configservice + - internal/service/comprehend patterns: - pattern: var $NAME = ... - metavariable-pattern: metavariable: $NAME patterns: - - pattern-regex: "(?i)ConfigService" + - pattern-regex: "(?i)Comprehend" severity: WARNING - - id: connect-in-func-name + - id: configservice-in-func-name languages: - go - message: Do not use "Connect" in func name inside connect package + message: Do not use "ConfigService" in func name inside configservice package paths: include: - - internal/service/connect + - internal/service/configservice patterns: - pattern: func $NAME( ... ) { ... } - metavariable-pattern: metavariable: $NAME patterns: - - pattern-regex: "(?i)Connect" - - pattern-not-regex: .*uickConnect.* + - pattern-regex: "(?i)ConfigService" - pattern-not-regex: ^TestAcc.* severity: WARNING - - id: connect-in-test-name + - id: configservice-in-test-name languages: - go - message: Include "Connect" in test name + message: Include "ConfigService" in test name paths: include: - - internal/service/connect/*_test.go + - internal/service/configservice/*_test.go patterns: - pattern: func $NAME( ... ) { ... } - metavariable-pattern: metavariable: $NAME patterns: - - pattern-not-regex: "^TestAccConnect" + - pattern-not-regex: "^TestAccConfigService" - pattern-regex: ^TestAcc.* severity: WARNING + - id: configservice-in-const-name + languages: + - go + message: Do not use "ConfigService" in const name inside configservice package + paths: + include: + - internal/service/configservice + patterns: + - pattern: const $NAME = ... + - metavariable-pattern: + metavariable: $NAME + patterns: + - pattern-regex: "(?i)ConfigService" + severity: WARNING diff --git a/.ci/.semgrep-service-name1.yml b/.ci/.semgrep-service-name1.yml index a1df360e29d..b5895bfc98b 100644 --- a/.ci/.semgrep-service-name1.yml +++ b/.ci/.semgrep-service-name1.yml @@ -1,5 +1,50 @@ # Generated by internal/generate/servicesemgrep/main.go; DO NOT EDIT. rules: + - id: configservice-in-var-name + languages: + - go + message: Do not use "ConfigService" in var name inside configservice package + paths: + include: + - internal/service/configservice + patterns: + - pattern: var $NAME = ... + - metavariable-pattern: + metavariable: $NAME + patterns: + - pattern-regex: "(?i)ConfigService" + severity: WARNING + - id: connect-in-func-name + languages: + - go + message: Do not use "Connect" in func name inside connect package + paths: + include: + - internal/service/connect + patterns: + - pattern: func $NAME( ... ) { ... } + - metavariable-pattern: + metavariable: $NAME + patterns: + - pattern-regex: "(?i)Connect" + - pattern-not-regex: .*uickConnect.* + - pattern-not-regex: ^TestAcc.* + severity: WARNING + - id: connect-in-test-name + languages: + - go + message: Include "Connect" in test name + paths: + include: + - internal/service/connect/*_test.go + patterns: + - pattern: func $NAME( ... ) { ... } + - metavariable-pattern: + metavariable: $NAME + patterns: + - pattern-not-regex: "^TestAccConnect" + - pattern-regex: ^TestAcc.* + severity: WARNING - id: connect-in-const-name languages: - go @@ -2957,33 +3002,3 @@ rules: patterns: - pattern-regex: "(?i)ImageBuilder" severity: WARNING - - id: inspector-in-func-name - languages: - - go - message: Do not use "Inspector" in func name inside inspector package - paths: - include: - - internal/service/inspector - patterns: - - pattern: func $NAME( ... ) { ... } - - metavariable-pattern: - metavariable: $NAME - patterns: - - pattern-regex: "(?i)Inspector" - - pattern-not-regex: ^TestAcc.* - severity: WARNING - - id: inspector-in-test-name - languages: - - go - message: Include "Inspector" in test name - paths: - include: - - internal/service/inspector/*_test.go - patterns: - - pattern: func $NAME( ... ) { ... } - - metavariable-pattern: - metavariable: $NAME - patterns: - - pattern-not-regex: "^TestAccInspector" - - pattern-regex: ^TestAcc.* - severity: WARNING diff --git a/.ci/.semgrep-service-name2.yml b/.ci/.semgrep-service-name2.yml index fea9f26de7d..375790c0ce9 100644 --- a/.ci/.semgrep-service-name2.yml +++ b/.ci/.semgrep-service-name2.yml @@ -1,5 +1,35 @@ # Generated by internal/generate/servicesemgrep/main.go; DO NOT EDIT. rules: + - id: inspector-in-func-name + languages: + - go + message: Do not use "Inspector" in func name inside inspector package + paths: + include: + - internal/service/inspector + patterns: + - pattern: func $NAME( ... ) { ... } + - metavariable-pattern: + metavariable: $NAME + patterns: + - pattern-regex: "(?i)Inspector" + - pattern-not-regex: ^TestAcc.* + severity: WARNING + - id: inspector-in-test-name + languages: + - go + message: Include "Inspector" in test name + paths: + include: + - internal/service/inspector/*_test.go + patterns: + - pattern: func $NAME( ... ) { ... } + - metavariable-pattern: + metavariable: $NAME + patterns: + - pattern-not-regex: "^TestAccInspector" + - pattern-regex: ^TestAcc.* + severity: WARNING - id: inspector-in-const-name languages: - go @@ -2968,17 +2998,3 @@ rules: patterns: - pattern-regex: "(?i)Redshift" severity: WARNING - - id: redshift-in-var-name - languages: - - go - message: Do not use "Redshift" in var name inside redshift package - paths: - include: - - internal/service/redshift - patterns: - - pattern: var $NAME = ... - - metavariable-pattern: - metavariable: $NAME - patterns: - - pattern-regex: "(?i)Redshift" - severity: WARNING diff --git a/.ci/.semgrep-service-name3.yml b/.ci/.semgrep-service-name3.yml index f953bae758f..25efae7d9b4 100644 --- a/.ci/.semgrep-service-name3.yml +++ b/.ci/.semgrep-service-name3.yml @@ -1,5 +1,19 @@ # Generated by internal/generate/servicesemgrep/main.go; DO NOT EDIT. rules: + - id: redshift-in-var-name + languages: + - go + message: Do not use "Redshift" in var name inside redshift package + paths: + include: + - internal/service/redshift + patterns: + - pattern: var $NAME = ... + - metavariable-pattern: + metavariable: $NAME + patterns: + - pattern-regex: "(?i)Redshift" + severity: WARNING - id: redshiftdata-in-func-name languages: - go diff --git a/.ci/.semgrep.yml b/.ci/.semgrep.yml index 0f042e76454..31bbb7f1bde 100644 --- a/.ci/.semgrep.yml +++ b/.ci/.semgrep.yml @@ -158,16 +158,18 @@ rules: - id: helper-schema-Set-extraneous-NewSet-with-flattenStringList languages: [go] - message: Prefer `flex.FlattenStringSet()` function for casting a list of string pointers to a set + message: Prefer `flex.FlattenStringSet()` or `flex.FlattenStringValueSet()` paths: include: - internal/ - pattern: schema.NewSet(schema.HashString, flex.FlattenStringList($APIOBJECT)) + patterns: + - pattern: schema.NewSet(schema.HashString, flex.FlattenStringList($APIOBJECT)) + - pattern: schema.NewSet(schema.HashString, flex.FlattenStringValueList($APIOBJECT)) severity: WARNING - id: helper-schema-Set-extraneous-expandStringList-with-List languages: [go] - message: Prefer `flex.ExpandStringSet()` function for casting a set to a list of string pointers + message: Prefer `flex.ExpandStringSet()` or `flex.ExpandStringValueSet()` paths: include: - internal/ @@ -178,6 +180,11 @@ rules: $LIST := $SET.List() ... flex.ExpandStringList($LIST) + - pattern: flex.ExpandStringValueList($SET.List()) + - pattern: | + $LIST := $SET.List() + ... + flex.ExpandStringValueList($LIST) severity: WARNING - id: helper-schema-ResourceData-GetOk-with-extraneous-conditional diff --git a/.teamcity/components/generated/services_all.kt b/.teamcity/components/generated/services_all.kt index e60565fe69f..7b72ad59654 100644 --- a/.teamcity/components/generated/services_all.kt +++ b/.teamcity/components/generated/services_all.kt @@ -42,6 +42,7 @@ val services = mapOf( "codestarnotifications" to ServiceSpec("CodeStar Notifications"), "cognitoidentity" to ServiceSpec("Cognito Identity"), "cognitoidp" to ServiceSpec("Cognito IDP (Identity Provider)"), + "comprehend" to ServiceSpec("Comprehend", parallelismOverride = 10), "configservice" to ServiceSpec("Config"), "connect" to ServiceSpec("Connect"), "cur" to ServiceSpec("Cost and Usage Report"), diff --git a/GNUmakefile b/GNUmakefile index d2b950e28a6..4c0f09c33d0 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -8,6 +8,7 @@ ACCTEST_PARALLELISM ?= 20 ifneq ($(origin PKG), undefined) PKG_NAME = internal/service/$(PKG) + TEST = ./$(PKG_NAME)/... endif ifneq ($(origin TESTS), undefined) diff --git a/docs/resource-name-generation.md b/docs/resource-name-generation.md index 8fd0cd6d6b2..ffede4dbf6c 100644 --- a/docs/resource-name-generation.md +++ b/docs/resource-name-generation.md @@ -65,7 +65,7 @@ func TestAccServiceThing_nameGenerated(t *testing.T) { Config: testAccThingConfig_nameGenerated(), Check: resource.ComposeTestCheckFunc( testAccCheckThingExists(resourceName, &thing), - create.TestCheckResourceAttrNameGenerated(resourceName, "name"), + acctest.CheckResourceAttrNameGenerated(resourceName, "name"), resource.TestCheckResourceAttr(resourceName, "name_prefix", resource.UniqueIdPrefix), ), }, @@ -93,7 +93,7 @@ func TestAccServiceThing_namePrefix(t *testing.T) { Config: testAccThingConfig_namePrefix("tf-acc-test-prefix-"), Check: resource.ComposeTestCheckFunc( testAccCheckThingExists(resourceName, &thing), - create.TestCheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), + acctest.CheckResourceAttrNameFromPrefix(resourceName, "name", "tf-acc-test-prefix-"), resource.TestCheckResourceAttr(resourceName, "name_prefix", "tf-acc-test-prefix-"), ), }, @@ -156,4 +156,4 @@ d.Set("name", resp.Name) d.Set("name_prefix", create.NamePrefixFromNameWithSuffix(aws.StringValue(resp.Name), ".fifo")) ``` -There are also functions `create.TestCheckResourceAttrNameWithSuffixGenerated` and `create.TestCheckResourceAttrNameWithSuffixFromPrefix` for use in tests. +There are also functions `acctest.CheckResourceAttrNameWithSuffixGenerated` and `acctest.CheckResourceAttrNameWithSuffixFromPrefix` for use in tests. diff --git a/go.mod b/go.mod index 40813efd742..2ae8a010210 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,9 @@ go 1.18 require ( github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 github.com/aws/aws-sdk-go v1.44.71 - github.com/aws/aws-sdk-go-v2 v1.16.9 + github.com/aws/aws-sdk-go-v2 v1.16.10 github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.10 + github.com/aws/aws-sdk-go-v2/service/comprehend v1.18.6 github.com/aws/aws-sdk-go-v2/service/fis v1.12.10 github.com/aws/aws-sdk-go-v2/service/kendra v1.31.2 github.com/aws/aws-sdk-go-v2/service/rolesanywhere v1.0.2 @@ -45,14 +46,14 @@ require ( github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/aws/aws-sdk-go-v2/config v1.15.4 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.16 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.11 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 // indirect github.com/aws/aws-sdk-go-v2/service/iam v1.18.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.4 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.11.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.16.4 // indirect - github.com/aws/smithy-go v1.12.0 // indirect + github.com/aws/smithy-go v1.12.1 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/evanphx/json-patch v0.5.2 // indirect @@ -93,4 +94,5 @@ require ( google.golang.org/genproto v0.0.0-20200711021454-869866162049 // indirect google.golang.org/grpc v1.48.0 // indirect google.golang.org/protobuf v1.28.0 // indirect + syreclabs.com/go/faker v1.2.3 ) diff --git a/go.sum b/go.sum index 966534ef968..7b2a9f2ff72 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,9 @@ github.com/aws/aws-sdk-go v1.44.71 h1:e5ZbeFAdDB9i7NcQWdmIiA/NOC4aWec3syOUtUE0dB github.com/aws/aws-sdk-go v1.44.71/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go-v2 v1.16.3/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU= github.com/aws/aws-sdk-go-v2 v1.16.8/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= -github.com/aws/aws-sdk-go-v2 v1.16.9 h1:Ezgkr/ByXA+5SASNJYLzA3kjbqXoho8QVDnCSHdgMBE= github.com/aws/aws-sdk-go-v2 v1.16.9/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw= +github.com/aws/aws-sdk-go-v2 v1.16.10 h1:+yDD0tcuHRQZgqONkpDwzepqmElQaSlFPymHRHR9mrc= +github.com/aws/aws-sdk-go-v2 v1.16.10/go.mod h1:WTACcleLz6VZTp7fak4EO5b9Q4foxbn+8PIz3PmyKlo= github.com/aws/aws-sdk-go-v2/config v1.15.4 h1:P4mesY1hYUxru4f9SU0XxNKXmzfxsD0FtMIPRBjkH7Q= github.com/aws/aws-sdk-go-v2/config v1.15.4/go.mod h1:ZijHHh0xd/A+ZY53az0qzC5tT46kt4JVCePf2NX9Lk4= github.com/aws/aws-sdk-go-v2/credentials v1.12.0 h1:4R/NqlcRFSkR0wxOhgHi+agGpbEr5qMCjn7VqUIJY+E= @@ -35,14 +36,18 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.10 h1:x6v/oELu+w/USy9D6dmoPE github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.10/go.mod h1:nWH+8PK9k4NLsOvOb3wtbFHiYeLXCxRokv4JnUN+wWs= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.10/go.mod h1:F+EZtuIwjlv35kRJPyBGcsA4f7bnSoz15zOQ2lJq1Z4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15/go.mod h1:pWrr2OoHlT7M/Pd2y4HV3gJyPb3qj5qMmnPkKSNPYK4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.16 h1:YVn7PaQ9La7tuTvKZGlXmzXkEHdbzHlKHeBrWCTtwtA= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.16/go.mod h1:GV1J/d4oB2fKCEoWRlYBOI6qzfpH8IXQN1d/caQGaMo= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.17 h1:U8DZvyFFesBmK62dYC6BRXm4Cd/wPP3aPcecu3xv/F4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.17/go.mod h1:6qtGip7sJEyvgsLjphRZWF9qPe3xJf1mL/MM01E35Wc= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.4/go.mod h1:8glyUqVIM4AmeenIsPo0oVh3+NUwnsQml2OFupfQW+0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.9/go.mod h1:08tUpeSGN33QKSO7fwxXczNfiwCpbj+GxK6XKwqWVv0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.10 h1:m7pKEgyn/TI2pn2WehrmJO4CKBaKvpkSLgnDR4nckC0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.10/go.mod h1:pucnblrb8XuRc/ZEi2S+jdQa3JVAfnwhytGgawh5pR4= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.11 h1:GMp98usVW5tzQhxd26KWhoNQPlR2noIlfbzqjVGBhLU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.11/go.mod h1:cYAfnB+9ZkmZWpQWmPDsuIGm4EA+6k2ZVtxKjw/XJBY= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11 h1:6cZRymlLEIlDTEB0+5+An6Zj1CKt6rSE69tOmFeu1nk= github.com/aws/aws-sdk-go-v2/internal/ini v1.3.11/go.mod h1:0MR+sS1b/yxsfAPvAESrw8NfwUoxMinDyw6EYR9BS2U= +github.com/aws/aws-sdk-go-v2/service/comprehend v1.18.6 h1:XbmxKUDU1GhcusWsvASyAomd0X2Qx0ROQjuZLEGKl/4= +github.com/aws/aws-sdk-go-v2/service/comprehend v1.18.6/go.mod h1:Netkj9MGMytRWgWfxPpjVCEvMTETtzYqr3AshAHOoOg= github.com/aws/aws-sdk-go-v2/service/fis v1.12.10 h1:JPBj3hpFRhV1AYDNIqnt8JD9eflH7gAWGNAtRETKWu8= github.com/aws/aws-sdk-go-v2/service/fis v1.12.10/go.mod h1:kkuTKync7QCaQnYM7KhlZvlEPQWldpAaxhzqVKUEaJI= github.com/aws/aws-sdk-go-v2/service/iam v1.18.4 h1:E41guA79mjEbwJdh0zXz1d8+Zt4zxRr+b1ipiVbKXzs= @@ -62,8 +67,9 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.16.4/go.mod h1:lfSYenAXtavyX2A1LsVig github.com/aws/aws-sdk-go-v2/service/transcribe v1.21.2 h1:tpxlVw/8WhfqUgY9Ia1BcrkwXRtYAOrgMupg4XHJ1GE= github.com/aws/aws-sdk-go-v2/service/transcribe v1.21.2/go.mod h1:RG8mbFe5gh0/r8LXxFjYt+GM5R2APw0VT91pvvEJ878= github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM= -github.com/aws/smithy-go v1.12.0 h1:gXpeZel/jPoWQ7OEmLIgCUnhkFftqNfwWUwAHSlp1v0= github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/aws/smithy-go v1.12.1 h1:yQRC55aXN/y1W10HgwHle01DRuV9Dpf31iGkotjt3Ag= +github.com/aws/smithy-go v1.12.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= @@ -420,3 +426,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +syreclabs.com/go/faker v1.2.3 h1:HPrWtnHazIf0/bVuPZJLFrtHlBHk10hS0SB+mV8v6R4= +syreclabs.com/go/faker v1.2.3/go.mod h1:NAXInmkPsC2xuO5MKZFe80PUXX5LU8cFdJIHGs+nSBE= diff --git a/internal/conns/awsclient_gen.go b/internal/conns/awsclient_gen.go index 4ea49b0b275..72e1947c442 100644 --- a/internal/conns/awsclient_gen.go +++ b/internal/conns/awsclient_gen.go @@ -4,6 +4,7 @@ package conns import ( "fmt" + "github.com/aws/aws-sdk-go-v2/service/comprehend" "github.com/aws/aws-sdk-go-v2/service/fis" "github.com/aws/aws-sdk-go-v2/service/kendra" "github.com/aws/aws-sdk-go-v2/service/rolesanywhere" @@ -75,7 +76,6 @@ import ( "github.com/aws/aws-sdk-go/service/cognitoidentity" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" "github.com/aws/aws-sdk-go/service/cognitosync" - "github.com/aws/aws-sdk-go/service/comprehend" "github.com/aws/aws-sdk-go/service/comprehendmedical" "github.com/aws/aws-sdk-go/service/computeoptimizer" "github.com/aws/aws-sdk-go/service/configservice" @@ -385,7 +385,7 @@ type AWSClient struct { CognitoIDPConn *cognitoidentityprovider.CognitoIdentityProvider CognitoIdentityConn *cognitoidentity.CognitoIdentity CognitoSyncConn *cognitosync.CognitoSync - ComprehendConn *comprehend.Comprehend + ComprehendConn *comprehend.Client ComprehendMedicalConn *comprehendmedical.ComprehendMedical ComputeOptimizerConn *computeoptimizer.ComputeOptimizer ConfigServiceConn *configservice.ConfigService diff --git a/internal/conns/config.go b/internal/conns/config.go index 2f05f3a3bf3..14dc26dd8ce 100644 --- a/internal/conns/config.go +++ b/internal/conns/config.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/aws/aws-sdk-go-v2/feature/ec2/imds" + "github.com/aws/aws-sdk-go-v2/service/comprehend" "github.com/aws/aws-sdk-go-v2/service/fis" "github.com/aws/aws-sdk-go-v2/service/kendra" "github.com/aws/aws-sdk-go-v2/service/rolesanywhere" @@ -194,6 +195,12 @@ func (c *Config) Client(ctx context.Context) (interface{}, diag.Diagnostics) { client.Session = sess client.TerraformVersion = c.TerraformVersion + client.ComprehendConn = comprehend.NewFromConfig(cfg, func(o *comprehend.Options) { + if endpoint := c.Endpoints[names.Comprehend]; endpoint != "" { + o.EndpointResolver = comprehend.EndpointResolverFromURL(endpoint) + } + }) + client.FISConn = fis.NewFromConfig(cfg, func(o *fis.Options) { if endpoint := c.Endpoints[names.FIS]; endpoint != "" { o.EndpointResolver = fis.EndpointResolverFromURL(endpoint) diff --git a/internal/conns/config_gen.go b/internal/conns/config_gen.go index 45a12941182..7e078fa6ff2 100644 --- a/internal/conns/config_gen.go +++ b/internal/conns/config_gen.go @@ -69,7 +69,6 @@ import ( "github.com/aws/aws-sdk-go/service/cognitoidentity" "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" "github.com/aws/aws-sdk-go/service/cognitosync" - "github.com/aws/aws-sdk-go/service/comprehend" "github.com/aws/aws-sdk-go/service/comprehendmedical" "github.com/aws/aws-sdk-go/service/computeoptimizer" "github.com/aws/aws-sdk-go/service/configservice" @@ -360,7 +359,6 @@ func (c *Config) clientConns(sess *session.Session) *AWSClient { CognitoIDPConn: cognitoidentityprovider.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints[names.CognitoIDP])})), CognitoIdentityConn: cognitoidentity.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints[names.CognitoIdentity])})), CognitoSyncConn: cognitosync.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints[names.CognitoSync])})), - ComprehendConn: comprehend.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints[names.Comprehend])})), ComprehendMedicalConn: comprehendmedical.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints[names.ComprehendMedical])})), ComputeOptimizerConn: computeoptimizer.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints[names.ComputeOptimizer])})), ConfigServiceConn: configservice.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints[names.ConfigService])})), diff --git a/internal/diag/append.go b/internal/diag/append.go new file mode 100644 index 00000000000..1e336acae7d --- /dev/null +++ b/internal/diag/append.go @@ -0,0 +1,18 @@ +package diag + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" +) + +func AppendWarningf(diags diag.Diagnostics, format string, a ...any) diag.Diagnostics { + return append(diags, diag.Diagnostic{ + Severity: diag.Warning, + Summary: fmt.Sprintf(format, a...), + }) +} + +func AppendErrorf(diags diag.Diagnostics, format string, a ...any) diag.Diagnostics { + return append(diags, diag.Errorf(format, a...)...) +} diff --git a/internal/generate/teamcity/acctest_services.hcl b/internal/generate/teamcity/acctest_services.hcl index a12527d130f..6af7df7f685 100644 --- a/internal/generate/teamcity/acctest_services.hcl +++ b/internal/generate/teamcity/acctest_services.hcl @@ -23,6 +23,10 @@ service "cloudhsmv2" { vpc_lock = true } +service "comprehend" { + parallelism = 10 +} + service "datasync" { vpc_lock = true } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index d47b93e53e7..f7f1c1065e7 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -56,6 +56,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/service/codestarnotifications" "github.com/hashicorp/terraform-provider-aws/internal/service/cognitoidentity" "github.com/hashicorp/terraform-provider-aws/internal/service/cognitoidp" + "github.com/hashicorp/terraform-provider-aws/internal/service/comprehend" "github.com/hashicorp/terraform-provider-aws/internal/service/configservice" "github.com/hashicorp/terraform-provider-aws/internal/service/connect" "github.com/hashicorp/terraform-provider-aws/internal/service/cur" @@ -1174,6 +1175,8 @@ func New(_ context.Context) (*schema.Provider, error) { "aws_cognito_user_pool_domain": cognitoidp.ResourceUserPoolDomain(), "aws_cognito_user_pool_ui_customization": cognitoidp.ResourceUserPoolUICustomization(), + "aws_comprehend_entity_recognizer": comprehend.ResourceEntityRecognizer(), + "aws_config_aggregate_authorization": configservice.ResourceAggregateAuthorization(), "aws_config_config_rule": configservice.ResourceConfigRule(), "aws_config_configuration_aggregator": configservice.ResourceConfigurationAggregator(), diff --git a/internal/service/comprehend/acc_test.go b/internal/service/comprehend/acc_test.go new file mode 100644 index 00000000000..f52bdec3e90 --- /dev/null +++ b/internal/service/comprehend/acc_test.go @@ -0,0 +1,58 @@ +package comprehend_test + +import ( + "context" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/comprehend" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" +) + +func testAccPreCheck(t *testing.T) { + conn := acctest.Provider.Meta().(*conns.AWSClient).ComprehendConn + ctx := context.Background() + + input := &comprehend.ListEntityRecognizersInput{} + + _, err := conn.ListEntityRecognizers(ctx, input) + + if acctest.PreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } + + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } +} + +func configVPCWithSubnetsAndDNS(rName string, subnetCount int) string { + return acctest.ConfigCompose( + acctest.ConfigAvailableAZsNoOptInDefaultExclude(), + fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + enable_dns_support = true + enable_dns_hostnames = true + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + count = %[2]d + + vpc_id = aws_vpc.test.id + availability_zone = element(data.aws_availability_zones.available.names, count.index) + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) + + tags = { + Name = %[1]q + } +} +`, rName, subnetCount), + ) +} diff --git a/internal/service/comprehend/common_model.go b/internal/service/comprehend/common_model.go new file mode 100644 index 00000000000..7fa0c1022f9 --- /dev/null +++ b/internal/service/comprehend/common_model.go @@ -0,0 +1,95 @@ +package comprehend + +import ( + "context" + "strings" + "sync" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" +) + +type safeMutex struct { + locked bool + mutex sync.Mutex +} + +func (m *safeMutex) Lock() { + m.mutex.Lock() + m.locked = true +} + +func (m *safeMutex) Unlock() { + if m.locked { + m.locked = false + m.mutex.Unlock() + } +} + +var modelVPCENILock safeMutex + +func findNetworkInterfaces(ctx context.Context, conn *ec2.EC2, securityGroups []string, subnets []string) ([]*ec2.NetworkInterface, error) { + networkInterfaces, err := tfec2.FindNetworkInterfacesWithContext(ctx, conn, &ec2.DescribeNetworkInterfacesInput{ + Filters: []*ec2.Filter{ + tfec2.NewFilter("group-id", securityGroups), + tfec2.NewFilter("subnet-id", subnets), + }, + }) + if err != nil { + return []*ec2.NetworkInterface{}, err + } + + comprehendENIs := make([]*ec2.NetworkInterface, 0, len(networkInterfaces)) + for _, v := range networkInterfaces { + if strings.HasSuffix(aws.ToString(v.RequesterId), ":Comprehend") { + comprehendENIs = append(comprehendENIs, v) + } + } + + return comprehendENIs, nil +} + +func waitNetworkInterfaceCreated(ctx context.Context, conn *ec2.EC2, initialENIIds map[string]bool, securityGroups []string, subnets []string, timeout time.Duration) (*ec2.NetworkInterface, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{}, + Target: []string{ec2.NetworkInterfaceStatusInUse}, + Refresh: statusNetworkInterfaces(ctx, conn, initialENIIds, securityGroups, subnets), + Delay: 4 * time.Minute, + MinTimeout: 10 * time.Second, + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*ec2.NetworkInterface); ok { + return output, err + } + + return nil, err +} + +func statusNetworkInterfaces(ctx context.Context, conn *ec2.EC2, initialENIs map[string]bool, securityGroups []string, subnets []string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + out, err := findNetworkInterfaces(ctx, conn, securityGroups, subnets) + if err != nil { + return nil, "", err + } + + var added *ec2.NetworkInterface + for _, v := range out { + if _, ok := initialENIs[aws.ToString(v.NetworkInterfaceId)]; !ok { + added = v + break + } + } + + if added == nil { + return nil, "", nil + } + + return added, aws.ToString(added.Status), nil + } +} diff --git a/internal/service/comprehend/consts.go b/internal/service/comprehend/consts.go new file mode 100644 index 00000000000..8c926987a46 --- /dev/null +++ b/internal/service/comprehend/consts.go @@ -0,0 +1,11 @@ +package comprehend + +import ( + "time" +) + +const iamPropagationTimeout = 2 * time.Minute + +// Avoid service throttling +const entityRegcognizerDelay = 1 * time.Minute +const entityRegcognizerPollInterval = 1 * time.Minute diff --git a/internal/service/comprehend/diff.go b/internal/service/comprehend/diff.go new file mode 100644 index 00000000000..014395c9c39 --- /dev/null +++ b/internal/service/comprehend/diff.go @@ -0,0 +1,51 @@ +package comprehend + +import ( + "regexp" + + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func diffSuppressKMSKeyId(k, oldValue, newValue string, d *schema.ResourceData) bool { + if oldValue == newValue { + return true + } + + oldId := oldValue + if arn.IsARN(oldValue) { + oldId = kmsKeyIdFromARN(oldValue) + } + + newId := newValue + if arn.IsARN(newValue) { + newId = kmsKeyIdFromARN(newValue) + } + + if oldId == newId { + return true + } + + return false +} + +func kmsKeyIdFromARN(s string) string { + arn, err := arn.Parse(s) + if err != nil { + return "" + } + + return kmsKeyIdFromARNResource(arn.Resource) +} + +func kmsKeyIdFromARNResource(s string) string { + re := regexp.MustCompile(`^key/(` + verify.UUIDRegexPattern + ")$") + matches := re.FindStringSubmatch(s) + if matches == nil || len(matches) != 2 { + return "" + } + + return matches[1] + +} diff --git a/internal/service/comprehend/diff_test.go b/internal/service/comprehend/diff_test.go new file mode 100644 index 00000000000..5bbad568065 --- /dev/null +++ b/internal/service/comprehend/diff_test.go @@ -0,0 +1,68 @@ +package comprehend + +import ( + "testing" +) + +func TestDiffSuppressKMSKeyId(t *testing.T) { + testcases := map[string]struct { + old string + new string + expectSuppress bool + }{ + "same ids": { + old: "57ff7a43-341d-46b6-aee3-a450c9de6dc8", + new: "57ff7a43-341d-46b6-aee3-a450c9de6dc8", + expectSuppress: true, + }, + "same arns": { + old: "arn:aws:kms:us-west-2:123456789012:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8", // lintignore:AWSAT003,AWSAT005 + new: "arn:aws:kms:us-west-2:123456789012:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8", // lintignore:AWSAT003,AWSAT005 + expectSuppress: true, + }, + + "different ids": { + old: "57ff7a43-341d-46b6-aee3-a450c9de6dc8", + new: "2fc6ef7b-7a71-4426-ad52-0840169767f1", + expectSuppress: false, + }, + "different arns": { + old: "arn:aws:kms:us-west-2:123456789012:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8", // lintignore:AWSAT003,AWSAT005 + new: "arn:aws:kms:us-west-2:123456789012:key/2fc6ef7b-7a71-4426-ad52-0840169767f1", // lintignore:AWSAT003,AWSAT005 + expectSuppress: false, + }, + + "id to equivalent arn": { + old: "57ff7a43-341d-46b6-aee3-a450c9de6dc8", + new: "arn:aws:kms:us-west-2:123456789012:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8", // lintignore:AWSAT003,AWSAT005 + expectSuppress: true, + }, + "arn to equivalent id": { + old: "arn:aws:kms:us-west-2:123456789012:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8", // lintignore:AWSAT003,AWSAT005 + new: "57ff7a43-341d-46b6-aee3-a450c9de6dc8", + expectSuppress: true, + }, + + "id to different arn": { + old: "57ff7a43-341d-46b6-aee3-a450c9de6dc8", + new: "arn:aws:kms:us-west-2:123456789012:key/2fc6ef7b-7a71-4426-ad52-0840169767f1", // lintignore:AWSAT003,AWSAT005 + expectSuppress: false, + }, + "arn to different id": { + old: "arn:aws:kms:us-west-2:123456789012:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8", // lintignore:AWSAT003,AWSAT005 + new: "2fc6ef7b-7a71-4426-ad52-0840169767f1", + expectSuppress: false, + }, + } + + for name, testcase := range testcases { + t.Run(name, func(t *testing.T) { + actual := diffSuppressKMSKeyId("field", testcase.old, testcase.new, nil) + + if e := testcase.expectSuppress; actual != e { + t.Fatalf("expected %t, got %t", e, actual) + } + }) + } + +} diff --git a/internal/service/comprehend/entity_recognizer.go b/internal/service/comprehend/entity_recognizer.go new file mode 100644 index 00000000000..119bf790db8 --- /dev/null +++ b/internal/service/comprehend/entity_recognizer.go @@ -0,0 +1,1091 @@ +package comprehend + +import ( + "context" + "errors" + "fmt" + "log" + "regexp" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/comprehend" + "github.com/aws/aws-sdk-go-v2/service/comprehend/types" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + awsdiag "github.com/hashicorp/terraform-provider-aws/internal/diag" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/flex" + tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func ResourceEntityRecognizer() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceEntityRecognizerCreate, + ReadWithoutTimeout: resourceEntityRecognizerRead, + UpdateWithoutTimeout: resourceEntityRecognizerUpdate, + DeleteWithoutTimeout: resourceEntityRecognizerDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "data_access_role_arn": { + Type: schema.TypeString, + Required: true, + }, + "input_data_config": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "annotations": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ExactlyOneOf: []string{"input_data_config.0.annotations", "input_data_config.0.entity_list"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "s3_uri": { + Type: schema.TypeString, + Required: true, + }, + "test_s3_uri": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "augmented_manifests": { + Type: schema.TypeSet, + Optional: true, + ExactlyOneOf: []string{"input_data_config.0.augmented_manifests", "input_data_config.0.documents"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "annotation_data_s3_uri": { + Type: schema.TypeString, + Optional: true, + }, + "attribute_names": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "document_type": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.AugmentedManifestsDocumentTypeFormat](), + Default: types.AugmentedManifestsDocumentTypeFormatPlainTextDocument, + }, + "s3_uri": { + Type: schema.TypeString, + Required: true, + }, + "source_documents_s3_uri": { + Type: schema.TypeString, + Optional: true, + }, + "split": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.Split](), + Default: types.SplitTrain, + }, + }, + }, + }, + "data_format": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.EntityRecognizerDataFormat](), + Default: types.EntityRecognizerDataFormatComprehendCsv, + }, + "documents": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ExactlyOneOf: []string{"input_data_config.0.documents", "input_data_config.0.augmented_manifests"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "input_format": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[types.InputFormat](), + Default: types.InputFormatOneDocPerLine, + }, + "s3_uri": { + Type: schema.TypeString, + Required: true, + }, + "test_s3_uri": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "entity_list": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + ExactlyOneOf: []string{"input_data_config.0.entity_list", "input_data_config.0.annotations"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "s3_uri": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "entity_types": { + Type: schema.TypeSet, + Required: true, + MaxItems: 25, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringIsNotEmpty, + validation.StringDoesNotContainAny("\n\r\t,"), + ), + }, + }, + }, + }, + }, + }, + }, + "language_code": { + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: enum.Validate[types.SyntaxLanguageCode](), + }, + "model_kms_key_id": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: diffSuppressKMSKeyId, + ValidateFunc: validateKMSKey, + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validModelName, + }, + "tags": tftags.TagsSchema(), + "tags_all": tftags.TagsSchemaComputed(), + "version_name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validModelVersionName, + ConflictsWith: []string{"version_name_prefix"}, + }, + "version_name_prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validModelVersionNamePrefix, + ConflictsWith: []string{"version_name"}, + }, + "volume_kms_key_id": { + Type: schema.TypeString, + Optional: true, + DiffSuppressFunc: diffSuppressKMSKeyId, + ValidateFunc: validateKMSKey, + }, + "vpc_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "security_group_ids": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "subnets": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + + CustomizeDiff: customdiff.All( + verify.SetTagsDiff, + func(_ context.Context, diff *schema.ResourceDiff, _ interface{}) error { + tfMap := getInputDataConfig(diff) + if tfMap == nil { + return nil + } + + if format := types.EntityRecognizerDataFormat(tfMap["data_format"].(string)); format == types.EntityRecognizerDataFormatComprehendCsv { + if tfMap["documents"] == nil { + return fmt.Errorf("documents must be set when data_format is %s", format) + } + } else { + if tfMap["augmented_manifests"] == nil { + return fmt.Errorf("augmented_manifests must be set when data_format is %s", format) + } + } + + return nil + }, + func(_ context.Context, diff *schema.ResourceDiff, _ interface{}) error { + tfMap := getInputDataConfig(diff) + if tfMap == nil { + return nil + } + + documents := expandDocuments(tfMap["documents"].([]interface{})) + if documents == nil { + return nil + } + + annotations := expandAnnotations(tfMap["annotations"].([]interface{})) + if annotations == nil { + return nil + } + + if documents.TestS3Uri != nil { + if annotations.TestS3Uri == nil { + return errors.New("input_data_config.annotations.test_s3_uri must be set when input_data_config.documents.test_s3_uri is set") + } + } else { + if annotations.TestS3Uri != nil { + return errors.New("input_data_config.documents.test_s3_uri must be set when input_data_config.annotations.test_s3_uri is set") + } + } + + return nil + }, + ), + } +} + +func resourceEntityRecognizerCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + awsClient := meta.(*conns.AWSClient) + conn := awsClient.ComprehendConn + + var versionName *string + raw := d.GetRawConfig().GetAttr("version_name") + if raw.IsNull() { + versionName = aws.String(create.Name("", d.Get("version_name_prefix").(string))) + } else if v := raw.AsString(); v != "" { + versionName = aws.String(v) + } + + diags := entityRecognizerPublishVersion(ctx, conn, d, versionName, create.ErrActionCreating, d.Timeout(schema.TimeoutCreate), awsClient) + if diags.HasError() { + return diags + } + + return append(diags, resourceEntityRecognizerRead(ctx, d, meta)...) +} + +func resourceEntityRecognizerRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).ComprehendConn + + out, err := FindEntityRecognizerByID(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Comprehend Entity Recognizer (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return diag.Errorf("reading Comprehend Entity Recognizer (%s): %s", d.Id(), err) + } + + d.Set("arn", out.EntityRecognizerArn) + d.Set("data_access_role_arn", out.DataAccessRoleArn) + d.Set("language_code", out.LanguageCode) + d.Set("model_kms_key_id", out.ModelKmsKeyId) + d.Set("version_name", out.VersionName) + d.Set("version_name_prefix", create.NamePrefixFromName(aws.ToString(out.VersionName))) + d.Set("volume_kms_key_id", out.VolumeKmsKeyId) + + // DescribeEntityRecognizer() doesn't return the model name + name, err := EntityRecognizerParseARN(aws.ToString(out.EntityRecognizerArn)) + if err != nil { + return diag.Errorf("reading Comprehend Entity Recognizer (%s): %s", d.Id(), err) + } + d.Set("name", name) + + if err := d.Set("input_data_config", flattenInputDataConfig(out.InputDataConfig)); err != nil { + return diag.Errorf("setting input_data_config: %s", err) + } + + if err := d.Set("vpc_config", flattenVPCConfig(out.VpcConfig)); err != nil { + return diag.Errorf("setting vpc_config: %s", err) + } + + tags, err := ListTags(ctx, conn, d.Id()) + if err != nil { + return diag.Errorf("listing tags for Comprehend Entity Recognizer (%s): %s", d.Id(), err) + } + + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return diag.Errorf("setting tags: %s", err) + } + + if err := d.Set("tags_all", tags.Map()); err != nil { + return diag.Errorf("setting tags_all: %s", err) + } + + return nil +} + +func resourceEntityRecognizerUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + awsClient := meta.(*conns.AWSClient) + conn := awsClient.ComprehendConn + + var diags diag.Diagnostics + + if d.HasChangesExcept("tags", "tags_all") { + var versionName *string + if d.HasChange("version_name") { + versionName = aws.String(d.Get("version_name").(string)) + } else if v := d.Get("version_name_prefix").(string); v != "" { + versionName = aws.String(create.Name("", d.Get("version_name_prefix").(string))) + } + + diags := entityRecognizerPublishVersion(ctx, conn, d, versionName, create.ErrActionUpdating, d.Timeout(schema.TimeoutUpdate), awsClient) + if diags.HasError() { + return diags + } + } else if d.HasChange("tags_all") { + // For a tags-only change. If tag changes are combined with version publishing, the tags are set + // by the CreateEntityRecognizer call + o, n := d.GetChange("tags_all") + + if err := UpdateTags(ctx, conn, d.Id(), o, n); err != nil { + return awsdiag.AppendErrorf(diags, "updating tags for Comprehend Entity Recognizer (%s): %s", d.Id(), err) + } + } + + return append(diags, resourceEntityRecognizerRead(ctx, d, meta)...) +} + +func resourceEntityRecognizerDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).ComprehendConn + + log.Printf("[INFO] Stopping Comprehend Entity Recognizer (%s)", d.Id()) + + _, err := conn.StopTrainingEntityRecognizer(ctx, &comprehend.StopTrainingEntityRecognizerInput{ + EntityRecognizerArn: aws.String(d.Id()), + }) + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil + } + + return diag.Errorf("stopping Comprehend Entity Recognizer (%s): %s", d.Id(), err) + } + + if _, err := waitEntityRecognizerStopped(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil + } + + return diag.Errorf("waiting for Comprehend Entity Recognizer (%s) to be stopped: %s", d.Id(), err) + } + + name, err := EntityRecognizerParseARN(d.Id()) + if err != nil { + return diag.Errorf("deleting Comprehend Entity Recognizer (%s): %s", d.Id(), err) + } + + log.Printf("[INFO] Deleting Comprehend Entity Recognizer (%s)", name) + + versions, err := ListEntityRecognizerVersionsByName(ctx, conn, name) + if err != nil { + return diag.Errorf("deleting Comprehend Entity Recognizer (%s): %s", name, err) + } + + var g multierror.Group + for _, v := range versions { + v := v + g.Go(func() error { + _, err = conn.DeleteEntityRecognizer(ctx, &comprehend.DeleteEntityRecognizerInput{ + EntityRecognizerArn: v.EntityRecognizerArn, + }) + if err != nil { + var nfe *types.ResourceNotFoundException + if !errors.As(err, &nfe) { + return fmt.Errorf("deleting version (%s): %w", aws.ToString(v.VersionName), err) + } + } + + if _, err := waitEntityRecognizerDeleted(ctx, conn, aws.ToString(v.EntityRecognizerArn), d.Timeout(schema.TimeoutDelete)); err != nil { + return fmt.Errorf("waiting for version (%s) to be deleted: %s", aws.ToString(v.VersionName), err) + } + + ec2Conn := meta.(*conns.AWSClient).EC2Conn + networkInterfaces, err := tfec2.FindNetworkInterfacesWithContext(ctx, ec2Conn, &ec2.DescribeNetworkInterfacesInput{ + Filters: []*ec2.Filter{ + tfec2.NewFilter(fmt.Sprintf("tag:%s", "tf-aws_comprehend_entity_recognizer"), []string{aws.ToString(v.EntityRecognizerArn)}), + }, + }) + if err != nil { + return fmt.Errorf("finding ENIs for version (%s): %w", aws.ToString(v.VersionName), err) + } + + for _, v := range networkInterfaces { + v := v + g.Go(func() error { + networkInterfaceID := aws.ToString(v.NetworkInterfaceId) + + if v.Attachment != nil { + err = tfec2.DetachNetworkInterfaceWithContext(ctx, ec2Conn, networkInterfaceID, aws.ToString(v.Attachment.AttachmentId), d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return fmt.Errorf("detaching ENI (%s): %w", networkInterfaceID, err) + } + } + + err = tfec2.DeleteNetworkInterfaceWithContext(ctx, ec2Conn, networkInterfaceID) + if err != nil { + return fmt.Errorf("deleting ENI (%s): %w", networkInterfaceID, err) + } + + return nil + }) + } + + return nil + }) + } + + if err := g.Wait(); err != nil { + return diag.Errorf("deleting Comprehend Entity Recognizer (%s): %s", name, err) + } + + return nil +} + +func entityRecognizerPublishVersion(ctx context.Context, conn *comprehend.Client, d *schema.ResourceData, versionName *string, action string, timeout time.Duration, awsClient *conns.AWSClient) diag.Diagnostics { + in := &comprehend.CreateEntityRecognizerInput{ + DataAccessRoleArn: aws.String(d.Get("data_access_role_arn").(string)), + InputDataConfig: expandInputDataConfig(getInputDataConfig(d)), + LanguageCode: types.LanguageCode(d.Get("language_code").(string)), + RecognizerName: aws.String(d.Get("name").(string)), + VersionName: versionName, + VpcConfig: expandVPCConfig(d.Get("vpc_config").([]interface{})), + ClientRequestToken: aws.String(resource.UniqueId()), + } + + if v, ok := d.Get("model_kms_key_id").(string); ok && v != "" { + in.ModelKmsKeyId = aws.String(v) + } + + if v, ok := d.Get("volume_kms_key_id").(string); ok && v != "" { + in.VolumeKmsKeyId = aws.String(v) + } + + defaultTagsConfig := awsClient.DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) + + if len(tags) > 0 { + in.Tags = Tags(tags.IgnoreAWS()) + } + + // Because the IAM credentials aren't evaluated until training time, we need to ensure we wait for the IAM propagation delay + time.Sleep(iamPropagationTimeout) + + if in.VpcConfig != nil { + modelVPCENILock.Lock() + defer modelVPCENILock.Unlock() + } + + var out *comprehend.CreateEntityRecognizerOutput + err := resource.RetryContext(ctx, timeout, func() *resource.RetryError { + var err error + out, err = conn.CreateEntityRecognizer(ctx, in) + + if err != nil { + var tmre *types.TooManyRequestsException + if errors.As(err, &tmre) { + return resource.RetryableError(err) + } else { + return resource.NonRetryableError(err) + } + } + + return nil + }) + if tfresource.TimedOut(err) { + out, err = conn.CreateEntityRecognizer(ctx, in) + } + if err != nil { + return diag.Errorf("%s Amazon Comprehend Entity Recognizer (%s): %s", action, d.Get("name").(string), err) + } + + if out == nil || out.EntityRecognizerArn == nil { + return diag.Errorf("%s Amazon Comprehend Entity Recognizer (%s): empty output", action, d.Get("name").(string)) + } + + d.SetId(aws.ToString(out.EntityRecognizerArn)) + + var g multierror.Group + waitCtx, cancel := context.WithCancel(ctx) + + g.Go(func() error { + _, err := waitEntityRecognizerCreated(waitCtx, conn, d.Id(), timeout) + cancel() + return err + }) + + var diags diag.Diagnostics + var tobe string + if action == create.ErrActionCreating { + tobe = "to be created" + } else if action == create.ErrActionUpdating { + tobe = "to be updated" + } else { + tobe = "to complete action" + } + + if in.VpcConfig != nil { + g.Go(func() error { + ec2Conn := awsClient.EC2Conn + enis, err := findNetworkInterfaces(waitCtx, ec2Conn, in.VpcConfig.SecurityGroupIds, in.VpcConfig.Subnets) + if err != nil { + diags = awsdiag.AppendWarningf(diags, "waiting for Amazon Comprehend Entity Recognizer (%s) %s: %s", d.Id(), tobe, err) + return nil + } + initialENIIds := make(map[string]bool, len(enis)) + for _, v := range enis { + initialENIIds[aws.ToString(v.NetworkInterfaceId)] = true + } + + newENI, err := waitNetworkInterfaceCreated(waitCtx, ec2Conn, initialENIIds, in.VpcConfig.SecurityGroupIds, in.VpcConfig.Subnets, d.Timeout(schema.TimeoutCreate)) + if errors.Is(err, context.Canceled) { + diags = awsdiag.AppendWarningf(diags, "waiting for Amazon Comprehend Entity Recognizer (%s) %s: %s", d.Id(), tobe, "ENI not found") + return nil + } + if err != nil { + diags = awsdiag.AppendWarningf(diags, "waiting for Amazon Comprehend Entity Recognizer (%s) %s: %s", d.Id(), tobe, err) + return nil + } + + modelVPCENILock.Unlock() + + _, err = ec2Conn.CreateTagsWithContext(waitCtx, &ec2.CreateTagsInput{ + Resources: []*string{newENI.NetworkInterfaceId}, + Tags: []*ec2.Tag{ + { + Key: aws.String("tf-aws_comprehend_entity_recognizer"), + Value: aws.String(d.Id()), + }, + }, + }) + if err != nil { + diags = awsdiag.AppendWarningf(diags, "waiting for Amazon Comprehend Entity Recognizer (%s) %s: %s", d.Id(), tobe, err) + return nil + } + + return nil + }) + } + + err = g.Wait().ErrorOrNil() + if err != nil { + diags = awsdiag.AppendErrorf(diags, "waiting for Amazon Comprehend Entity Recognizer (%s) %s: %s", d.Id(), tobe, err) + } + + return diags +} + +func FindEntityRecognizerByID(ctx context.Context, conn *comprehend.Client, id string) (*types.EntityRecognizerProperties, error) { + in := &comprehend.DescribeEntityRecognizerInput{ + EntityRecognizerArn: aws.String(id), + } + + out, err := conn.DescribeEntityRecognizer(ctx, in) + if err != nil { + var nfe *types.ResourceNotFoundException + if errors.As(err, &nfe) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + return nil, err + } + + if out == nil || out.EntityRecognizerProperties == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out.EntityRecognizerProperties, nil +} + +func ListEntityRecognizerVersionsByName(ctx context.Context, conn *comprehend.Client, name string) ([]types.EntityRecognizerProperties, error) { + results := []types.EntityRecognizerProperties{} + + input := &comprehend.ListEntityRecognizersInput{ + Filter: &types.EntityRecognizerFilter{ + RecognizerName: aws.String(name), + }, + } + paginator := comprehend.NewListEntityRecognizersPaginator(conn, input) + for paginator.HasMorePages() { + output, err := paginator.NextPage(ctx) + if err != nil { + return []types.EntityRecognizerProperties{}, err + } + results = append(results, output.EntityRecognizerPropertiesList...) + } + + return results, nil +} + +func waitEntityRecognizerCreated(ctx context.Context, conn *comprehend.Client, id string, timeout time.Duration) (*types.EntityRecognizerProperties, error) { + stateConf := &resource.StateChangeConf{ + Pending: enum.Slice(types.ModelStatusSubmitted, types.ModelStatusTraining), + Target: enum.Slice(types.ModelStatusTrained), + Refresh: statusEntityRecognizer(ctx, conn, id), + Delay: entityRegcognizerDelay, + PollInterval: entityRegcognizerPollInterval, + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*types.EntityRecognizerProperties); ok { + var ues *resource.UnexpectedStateError + if errors.As(err, &ues) { + if ues.State == string(types.ModelStatusInError) { + err = errors.New(aws.ToString(out.Message)) + } + } + return out, err + } + + return nil, err +} + +func waitEntityRecognizerStopped(ctx context.Context, conn *comprehend.Client, id string, timeout time.Duration) (*types.EntityRecognizerProperties, error) { + stateConf := &resource.StateChangeConf{ + Pending: enum.Slice(types.ModelStatusSubmitted, types.ModelStatusTraining, types.ModelStatusStopRequested), + Target: enum.Slice(types.ModelStatusTrained, types.ModelStatusStopped, types.ModelStatusInError, types.ModelStatusDeleting), + Refresh: statusEntityRecognizer(ctx, conn, id), + PollInterval: entityRegcognizerPollInterval, + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*types.EntityRecognizerProperties); ok { + return out, err + } + + return nil, err +} + +func waitEntityRecognizerDeleted(ctx context.Context, conn *comprehend.Client, id string, timeout time.Duration) (*types.EntityRecognizerProperties, error) { + stateConf := &resource.StateChangeConf{ + Pending: enum.Slice(types.ModelStatusSubmitted, types.ModelStatusTraining, types.ModelStatusDeleting, types.ModelStatusInError, types.ModelStatusStopRequested), + Target: []string{}, + Refresh: statusEntityRecognizer(ctx, conn, id), + Delay: entityRegcognizerDelay, + PollInterval: entityRegcognizerPollInterval, + NotFoundChecks: 3, + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*types.EntityRecognizerProperties); ok { + return out, err + } + + return nil, err +} + +func statusEntityRecognizer(ctx context.Context, conn *comprehend.Client, id string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + out, err := FindEntityRecognizerByID(ctx, conn, id) + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return out, string(out.Status), nil + } +} + +func flattenInputDataConfig(apiObject *types.EntityRecognizerInputDataConfig) []interface{} { + if apiObject == nil { + return nil + } + + m := map[string]interface{}{ + "entity_types": flattenEntityTypes(apiObject.EntityTypes), + "annotations": flattenAnnotations(apiObject.Annotations), + "augmented_manifests": flattenAugmentedManifests(apiObject.AugmentedManifests), + "data_format": apiObject.DataFormat, + "documents": flattenDocuments(apiObject.Documents), + "entity_list": flattenEntityList(apiObject.EntityList), + } + + return []interface{}{m} +} + +func flattenEntityTypes(apiObjects []types.EntityTypesListItem) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var l []interface{} + + for _, apiObject := range apiObjects { + l = append(l, flattenEntityTypesListItem(&apiObject)) + } + + return l +} + +func flattenEntityTypesListItem(apiObject *types.EntityTypesListItem) map[string]interface{} { + if apiObject == nil { + return nil + } + + m := map[string]interface{}{ + "type": aws.ToString(apiObject.Type), + } + + return m +} + +func flattenAnnotations(apiObject *types.EntityRecognizerAnnotations) []interface{} { + if apiObject == nil { + return nil + } + + m := map[string]interface{}{ + "s3_uri": aws.ToString(apiObject.S3Uri), + } + + if v := apiObject.TestS3Uri; v != nil { + m["test_s3_uri"] = aws.ToString(v) + } + + return []interface{}{m} +} + +func flattenAugmentedManifests(apiObjects []types.AugmentedManifestsListItem) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var l []interface{} + + for _, apiObject := range apiObjects { + l = append(l, flattenAugmentedManifestsListItem(&apiObject)) + } + + return l +} + +func flattenAugmentedManifestsListItem(apiObject *types.AugmentedManifestsListItem) map[string]interface{} { + if apiObject == nil { + return nil + } + + m := map[string]interface{}{ + "attribute_names": flex.FlattenStringValueList(apiObject.AttributeNames), + "s3_uri": aws.ToString(apiObject.S3Uri), + "document_type": apiObject.DocumentType, + "split": apiObject.Split, + } + + if v := apiObject.AnnotationDataS3Uri; v != nil { + m["annotation_data_s3_uri"] = aws.ToString(v) + } + + if v := apiObject.SourceDocumentsS3Uri; v != nil { + m["source_documents_s3_uri"] = aws.ToString(v) + } + + return m +} + +func flattenDocuments(apiObject *types.EntityRecognizerDocuments) []interface{} { + if apiObject == nil { + return nil + } + + m := map[string]interface{}{ + "s3_uri": aws.ToString(apiObject.S3Uri), + "input_format": apiObject.InputFormat, + } + + if v := apiObject.TestS3Uri; v != nil { + m["test_s3_uri"] = aws.ToString(v) + } + + return []interface{}{m} +} + +func flattenEntityList(apiObject *types.EntityRecognizerEntityList) []interface{} { + if apiObject == nil { + return nil + } + + m := map[string]interface{}{ + "s3_uri": aws.ToString(apiObject.S3Uri), + } + + return []interface{}{m} +} + +func flattenVPCConfig(apiObject *types.VpcConfig) []interface{} { + if apiObject == nil { + return nil + } + + m := map[string]interface{}{ + "security_group_ids": flex.FlattenStringValueSet(apiObject.SecurityGroupIds), + "subnets": flex.FlattenStringValueSet(apiObject.Subnets), + } + + return []interface{}{m} +} + +type resourceGetter interface { + Get(key string) any +} + +func getInputDataConfig(diff resourceGetter) map[string]any { + v := diff.Get("input_data_config").([]any) + if len(v) == 0 { + return nil + } + + return v[0].(map[string]any) +} + +func expandInputDataConfig(tfMap map[string]any) *types.EntityRecognizerInputDataConfig { + if len(tfMap) == 0 { + return nil + } + + a := &types.EntityRecognizerInputDataConfig{ + EntityTypes: expandEntityTypes(tfMap["entity_types"].(*schema.Set)), + Annotations: expandAnnotations(tfMap["annotations"].([]interface{})), + AugmentedManifests: expandAugmentedManifests(tfMap["augmented_manifests"].(*schema.Set)), + DataFormat: types.EntityRecognizerDataFormat(tfMap["data_format"].(string)), + Documents: expandDocuments(tfMap["documents"].([]interface{})), + EntityList: expandEntityList(tfMap["entity_list"].([]interface{})), + } + + return a +} + +func expandEntityTypes(tfSet *schema.Set) []types.EntityTypesListItem { + if tfSet.Len() == 0 { + return nil + } + + var s []types.EntityTypesListItem + + for _, r := range tfSet.List() { + m, ok := r.(map[string]interface{}) + if !ok { + continue + } + + a := expandEntityTypesListItem(m) + if a == nil { + continue + } + + s = append(s, *a) + } + + return s +} + +func expandEntityTypesListItem(tfMap map[string]interface{}) *types.EntityTypesListItem { + if tfMap == nil { + return nil + } + + a := &types.EntityTypesListItem{} + + if v, ok := tfMap["type"].(string); ok && v != "" { + a.Type = aws.String(v) + } + + return a +} + +func expandAnnotations(tfList []interface{}) *types.EntityRecognizerAnnotations { + if len(tfList) == 0 { + return nil + } + + tfMap := tfList[0].(map[string]interface{}) + + a := &types.EntityRecognizerAnnotations{ + S3Uri: aws.String(tfMap["s3_uri"].(string)), + } + + if v, ok := tfMap["test_s3_uri"].(string); ok && v != "" { + a.TestS3Uri = aws.String(v) + } + + return a +} + +func expandAugmentedManifests(tfSet *schema.Set) []types.AugmentedManifestsListItem { + if tfSet.Len() == 0 { + return nil + } + + var s []types.AugmentedManifestsListItem + + for _, r := range tfSet.List() { + m, ok := r.(map[string]interface{}) + + if !ok { + continue + } + + a := expandAugmentedManifestsListItem(m) + + if a == nil { + continue + } + + s = append(s, *a) + } + + return s +} + +func expandAugmentedManifestsListItem(tfMap map[string]interface{}) *types.AugmentedManifestsListItem { + if tfMap == nil { + return nil + } + + a := &types.AugmentedManifestsListItem{ + AttributeNames: flex.ExpandStringValueList(tfMap["attribute_names"].([]interface{})), + S3Uri: aws.String(tfMap["s3_uri"].(string)), + DocumentType: types.AugmentedManifestsDocumentTypeFormat(tfMap["document_type"].(string)), + Split: types.Split(tfMap["split"].(string)), + } + + if v, ok := tfMap["annotation_data_s3_uri"].(string); ok && v != "" { + a.AnnotationDataS3Uri = aws.String(v) + } + + if v, ok := tfMap["source_documents_s3_uri"].(string); ok && v != "" { + a.SourceDocumentsS3Uri = aws.String(v) + } + + return a +} + +func expandDocuments(tfList []interface{}) *types.EntityRecognizerDocuments { + if len(tfList) == 0 { + return nil + } + + tfMap := tfList[0].(map[string]interface{}) + + a := &types.EntityRecognizerDocuments{ + S3Uri: aws.String(tfMap["s3_uri"].(string)), + InputFormat: types.InputFormat(tfMap["input_format"].(string)), + } + + if v, ok := tfMap["test_s3_uri"].(string); ok && v != "" { + a.TestS3Uri = aws.String(v) + } + + return a +} + +func expandEntityList(tfList []interface{}) *types.EntityRecognizerEntityList { + if len(tfList) == 0 { + return nil + } + + tfMap := tfList[0].(map[string]interface{}) + + a := &types.EntityRecognizerEntityList{ + S3Uri: aws.String(tfMap["s3_uri"].(string)), + } + + return a +} + +func expandVPCConfig(tfList []interface{}) *types.VpcConfig { + if len(tfList) == 0 { + return nil + } + + tfMap := tfList[0].(map[string]interface{}) + + a := &types.VpcConfig{ + SecurityGroupIds: flex.ExpandStringValueSet(tfMap["security_group_ids"].(*schema.Set)), + Subnets: flex.ExpandStringValueSet(tfMap["subnets"].(*schema.Set)), + } + + return a +} + +func EntityRecognizerParseARN(arnString string) (string, error) { + arn, err := arn.Parse(arnString) + if err != nil { + return "", err + } + re := regexp.MustCompile(`^entity-recognizer/([[:alnum:]-]+)`) + matches := re.FindStringSubmatch(arn.Resource) + if len(matches) != 2 { + return "", fmt.Errorf("unable to parse %q", arnString) + } + name := matches[1] + + return name, nil +} diff --git a/internal/service/comprehend/entity_recognizer_test.go b/internal/service/comprehend/entity_recognizer_test.go new file mode 100644 index 00000000000..5632b68fc21 --- /dev/null +++ b/internal/service/comprehend/entity_recognizer_test.go @@ -0,0 +1,2306 @@ +package comprehend_test + +import ( + "context" + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/comprehend" + "github.com/aws/aws-sdk-go-v2/service/comprehend/types" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfcomprehend "github.com/hashicorp/terraform-provider-aws/internal/service/comprehend" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccComprehendEntityRecognizer_basic(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "data_access_role_arn", "aws_iam_role.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "comprehend", regexp.MustCompile(fmt.Sprintf(`entity-recognizer/%s/version/%s$`, rName, uniqueIDPattern()))), + resource.TestCheckResourceAttr(resourceName, "input_data_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.entity_types.#", "2"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.annotations.#", "0"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.augmented_manifests.#", "0"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.data_format", string(types.EntityRecognizerDataFormatComprehendCsv)), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.documents.#", "1"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.documents.0.input_format", string(types.InputFormatOneDocPerLine)), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.documents.0.test_s3_uri", ""), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.entity_list.#", "1"), + resource.TestCheckResourceAttr(resourceName, "language_code", "en"), + resource.TestCheckResourceAttr(resourceName, "model_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags_all.%", "0"), + acctest.CheckResourceAttrNameGenerated(resourceName, "version_name"), + resource.TestCheckResourceAttr(resourceName, "version_name_prefix", resource.UniqueIdPrefix), + resource.TestCheckResourceAttr(resourceName, "volume_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_disappears(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + acctest.CheckResourceDisappears(acctest.Provider, tfcomprehend.ResourceEntityRecognizer(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_versionName(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vName1 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vName2 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_versionName(rName, vName1, "key", "value1"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "version_name", vName1), + resource.TestCheckResourceAttr(resourceName, "version_name_prefix", ""), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "comprehend", regexp.MustCompile(fmt.Sprintf(`entity-recognizer/%s/version/%s$`, rName, vName1))), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccEntityRecognizerConfig_versionName(rName, vName2, "key", "value2"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 2), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "version_name", vName2), + resource.TestCheckResourceAttr(resourceName, "version_name_prefix", ""), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "comprehend", regexp.MustCompile(fmt.Sprintf(`entity-recognizer/%s/version/%s$`, rName, vName2))), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key", "value2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_versionNameEmpty(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_versionNameEmpty(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "version_name", ""), + resource.TestCheckResourceAttr(resourceName, "version_name_prefix", ""), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "comprehend", regexp.MustCompile(fmt.Sprintf(`entity-recognizer/%s$`, rName))), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_versionNameGenerated(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_versionNameNotSet(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + acctest.CheckResourceAttrNameGenerated(resourceName, "version_name"), + resource.TestCheckResourceAttr(resourceName, "version_name_prefix", resource.UniqueIdPrefix), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "comprehend", regexp.MustCompile(fmt.Sprintf(`entity-recognizer/%s/version/%s$`, rName, uniqueIDPattern()))), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_versionNamePrefix(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_versioNamePrefix(rName, "tf-acc-test-prefix-"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + acctest.CheckResourceAttrNameFromPrefix(resourceName, "version_name", "tf-acc-test-prefix-"), + resource.TestCheckResourceAttr(resourceName, "version_name_prefix", "tf-acc-test-prefix-"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "comprehend", regexp.MustCompile(fmt.Sprintf(`entity-recognizer/%s/version/%s$`, rName, prefixedUniqueIDPattern("tf-acc-test-prefix-")))), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_documents_testDocuments(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_testDocuments(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "name", rName), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "comprehend", regexp.MustCompile(fmt.Sprintf(`entity-recognizer/%s/version/%s$`, rName, uniqueIDPattern()))), + resource.TestCheckResourceAttr(resourceName, "input_data_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.entity_types.#", "2"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.annotations.#", "0"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.augmented_manifests.#", "0"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.data_format", string(types.EntityRecognizerDataFormatComprehendCsv)), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.documents.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "input_data_config.0.documents.0.test_s3_uri"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.entity_list.#", "1"), + resource.TestCheckResourceAttr(resourceName, "language_code", "en"), + resource.TestCheckResourceAttr(resourceName, "model_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags_all.%", "0"), + acctest.CheckResourceAttrNameGenerated(resourceName, "version_name"), + resource.TestCheckResourceAttr(resourceName, "version_name_prefix", resource.UniqueIdPrefix), + resource.TestCheckResourceAttr(resourceName, "volume_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_annotations_basic(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_annotations_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "data_access_role_arn", "aws_iam_role.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "comprehend", regexp.MustCompile(fmt.Sprintf(`entity-recognizer/%s/version/%s$`, rName, uniqueIDPattern()))), + resource.TestCheckResourceAttr(resourceName, "input_data_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.entity_types.#", "2"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.annotations.#", "1"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.augmented_manifests.#", "0"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.data_format", string(types.EntityRecognizerDataFormatComprehendCsv)), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.documents.#", "1"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.documents.0.input_format", string(types.InputFormatOneDocPerLine)), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.documents.0.test_s3_uri", ""), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.entity_list.#", "0"), + resource.TestCheckResourceAttr(resourceName, "language_code", "en"), + resource.TestCheckResourceAttr(resourceName, "model_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags_all.%", "0"), + acctest.CheckResourceAttrNameGenerated(resourceName, "version_name"), + resource.TestCheckResourceAttr(resourceName, "version_name_prefix", resource.UniqueIdPrefix), + resource.TestCheckResourceAttr(resourceName, "volume_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_annotations_testDocuments(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_annotations_testDocuments(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "data_access_role_arn", "aws_iam_role.test", "arn"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "comprehend", regexp.MustCompile(fmt.Sprintf(`entity-recognizer/%s/version/%s$`, rName, uniqueIDPattern()))), + resource.TestCheckResourceAttr(resourceName, "input_data_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.entity_types.#", "2"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.annotations.#", "1"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.augmented_manifests.#", "0"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.data_format", string(types.EntityRecognizerDataFormatComprehendCsv)), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.documents.#", "1"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.documents.0.input_format", string(types.InputFormatOneDocPerLine)), + resource.TestCheckResourceAttrSet(resourceName, "input_data_config.0.documents.0.test_s3_uri"), + resource.TestCheckResourceAttr(resourceName, "input_data_config.0.entity_list.#", "0"), + resource.TestCheckResourceAttr(resourceName, "language_code", "en"), + resource.TestCheckResourceAttr(resourceName, "model_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags_all.%", "0"), + acctest.CheckResourceAttrNameGenerated(resourceName, "version_name"), + resource.TestCheckResourceAttr(resourceName, "version_name_prefix", resource.UniqueIdPrefix), + resource.TestCheckResourceAttr(resourceName, "volume_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_annotations_validateNoTestDocuments(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_annotations_noTestDocuments(rName), + ExpectError: regexp.MustCompile("input_data_config.documents.test_s3_uri must be set when input_data_config.annotations.test_s3_uri is set"), + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_annotations_validateNoTestAnnotations(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_annotations_noTestAnnotations(rName), + ExpectError: regexp.MustCompile("input_data_config.annotations.test_s3_uri must be set when input_data_config.documents.test_s3_uri is set"), + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_KMSKeys_CreateIDs(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_kmsKeyIds(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttrPair(resourceName, "model_kms_key_id", "aws_kms_key.model", "key_id"), + resource.TestCheckResourceAttrPair(resourceName, "volume_kms_key_id", "aws_kms_key.volume", "key_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccEntityRecognizerConfig_kmsKeyARNs(rName), + PlanOnly: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_KMSKeys_CreateARNs(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var entityrecognizer types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_kmsKeyARNs(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &entityrecognizer), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttrPair(resourceName, "model_kms_key_id", "aws_kms_key.model", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "volume_kms_key_id", "aws_kms_key.volume", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccEntityRecognizerConfig_kmsKeyIds(rName), + PlanOnly: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_KMSKeys_Update(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var v1, v2, v3, v4 types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_kmsKeys_None(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v1), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "model_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "volume_kms_key_id", ""), + ), + }, + { + Config: testAccEntityRecognizerConfig_kmsKeys_Set(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v2), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 2), + resource.TestCheckResourceAttrPair(resourceName, "model_kms_key_id", "aws_kms_key.model", "key_id"), + resource.TestCheckResourceAttrPair(resourceName, "volume_kms_key_id", "aws_kms_key.volume", "key_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccEntityRecognizerConfig_kmsKeys_Update(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v3), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 3), + resource.TestCheckResourceAttrPair(resourceName, "model_kms_key_id", "aws_kms_key.model2", "key_id"), + resource.TestCheckResourceAttrPair(resourceName, "volume_kms_key_id", "aws_kms_key.volume2", "key_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccEntityRecognizerConfig_kmsKeys_None(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v4), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 4), + resource.TestCheckResourceAttr(resourceName, "model_kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "volume_kms_key_id", ""), + ), + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_VPCConfig_Create(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var er1, er2 types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_vpcConfig(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &er1), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "vpc_config.0.security_group_ids.*", "aws_security_group.test.0", "id"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.0.subnets.#", "2"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "vpc_config.0.subnets.*", "aws_subnet.test.0", "id"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "vpc_config.0.subnets.*", "aws_subnet.test.1", "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccEntityRecognizerConfig_vpcConfig_Update(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &er2), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 2), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "vpc_config.0.security_group_ids.*", "aws_security_group.test.1", "id"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.0.subnets.#", "2"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "vpc_config.0.subnets.*", "aws_subnet.test.2", "id"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "vpc_config.0.subnets.*", "aws_subnet.test.3", "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_VPCConfig_Update(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var er1, er2, er3 types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_vpcConfig_None(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &er1), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "0"), + ), + }, + { + Config: testAccEntityRecognizerConfig_vpcConfig(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &er2), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 2), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.0.security_group_ids.#", "1"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "vpc_config.0.security_group_ids.*", "aws_security_group.test.0", "id"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.0.subnets.#", "2"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "vpc_config.0.subnets.*", "aws_subnet.test.0", "id"), + resource.TestCheckTypeSetElemAttrPair(resourceName, "vpc_config.0.subnets.*", "aws_subnet.test.1", "id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccEntityRecognizerConfig_vpcConfig_None(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &er3), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 3), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_tags(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var v1, v2, v3 types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEntityRecognizerConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v1), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccEntityRecognizerConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v2), + testAccCheckEntityRecognizerNotRecreated(&v1, &v2), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccEntityRecognizerConfig_tags1(rName, "key2", "value2"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v3), + testAccCheckEntityRecognizerNotRecreated(&v2, &v3), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func TestAccComprehendEntityRecognizer_DefaultTags_providerOnly(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var v1, v2, v3 types.EntityRecognizerProperties + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_comprehend_entity_recognizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + acctest.PreCheckPartitionHasService(names.ComprehendEndpointID, t) + testAccPreCheck(t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ComprehendEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckEntityRecognizerDestroy, + Steps: []resource.TestStep{ + { + Config: acctest.ConfigCompose( + acctest.ConfigDefaultTags_Tags1("providerkey1", "providervalue1"), + testAccEntityRecognizerConfig_tags0(rName), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v1), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey1", "providervalue1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: acctest.ConfigCompose( + acctest.ConfigDefaultTags_Tags2("providerkey1", "providervalue1", "providerkey2", "providervalue2"), + testAccEntityRecognizerConfig_tags0(rName), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v2), + testAccCheckEntityRecognizerNotRecreated(&v1, &v2), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags_all.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey1", "providervalue1"), + resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey2", "providervalue2"), + ), + }, + { + Config: acctest.ConfigCompose( + acctest.ConfigDefaultTags_Tags1("providerkey1", "value1"), + testAccEntityRecognizerConfig_tags0(rName), + ), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckEntityRecognizerExists(resourceName, &v3), + testAccCheckEntityRecognizerNotRecreated(&v2, &v3), + testAccCheckEntityRecognizerPublishedVersions(resourceName, 1), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags_all.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags_all.providerkey1", "value1"), + ), + }, + }, + }) +} + +func testAccCheckEntityRecognizerDestroy(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ComprehendConn + ctx := context.Background() + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_comprehend_entity_recognizer" { + continue + } + + name, err := tfcomprehend.EntityRecognizerParseARN(rs.Primary.ID) + if err != nil { + return err + } + + input := &comprehend.ListEntityRecognizersInput{ + Filter: &types.EntityRecognizerFilter{ + RecognizerName: aws.String(name), + }, + } + total := 0 + paginator := comprehend.NewListEntityRecognizersPaginator(conn, input) + for paginator.HasMorePages() { + output, err := paginator.NextPage(ctx) + if err != nil { + return err + } + total += len(output.EntityRecognizerPropertiesList) + } + + if total != 0 { + return fmt.Errorf("Expected Comprehend Entity Recognizer (%s) to be destroyed, found %d versions", rs.Primary.ID, total) + } + return nil + } + + return nil +} + +func testAccCheckEntityRecognizerExists(name string, entityrecognizer *types.EntityRecognizerProperties) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Comprehend Entity Recognizer is set") + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ComprehendConn + ctx := context.Background() + + resp, err := tfcomprehend.FindEntityRecognizerByID(ctx, conn, rs.Primary.ID) + if err != nil { + return fmt.Errorf("Error describing Comprehend Entity Recognizer: %w", err) + } + + *entityrecognizer = *resp + + return nil + } +} + +// func testAccCheckEntityRecognizerRecreated(before, after *types.EntityRecognizerProperties) resource.TestCheckFunc { +// return func(s *terraform.State) error { +// if entityRecognizerIdentity(before, after) { +// return fmt.Errorf("Comprehend Entity Recognizer not recreated") +// } + +// return nil +// } +// } + +func testAccCheckEntityRecognizerNotRecreated(before, after *types.EntityRecognizerProperties) resource.TestCheckFunc { + return func(s *terraform.State) error { + if !entityRecognizerIdentity(before, after) { + return fmt.Errorf("Comprehend Entity Recognizer recreated") + } + + return nil + } +} + +func entityRecognizerIdentity(before, after *types.EntityRecognizerProperties) bool { + return aws.ToTime(before.SubmitTime).Equal(aws.ToTime(after.SubmitTime)) +} + +func uniqueIDPattern() string { + return prefixedUniqueIDPattern(resource.UniqueIdPrefix) +} + +func prefixedUniqueIDPattern(prefix string) string { + return fmt.Sprintf("%s[[:xdigit:]]{%d}", prefix, resource.UniqueIDSuffixLength) +} + +func testAccCheckEntityRecognizerPublishedVersions(name string, expected int) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Comprehend Entity Recognizer is set") + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ComprehendConn + ctx := context.Background() + + name, err := tfcomprehend.EntityRecognizerParseARN(rs.Primary.ID) + if err != nil { + return err + } + + input := &comprehend.ListEntityRecognizersInput{ + Filter: &types.EntityRecognizerFilter{ + RecognizerName: aws.String(name), + }, + } + count := 0 + paginator := comprehend.NewListEntityRecognizersPaginator(conn, input) + for paginator.HasMorePages() { + output, err := paginator.NextPage(ctx) + if err != nil { + return err + } + count += len(output.EntityRecognizerPropertiesList) + } + + if count != expected { + return fmt.Errorf("expected %d published versions, found %d", expected, count) + } + + return nil + } +} + +func testAccEntityRecognizerConfig_basic(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_versionName(rName, vName, key, value string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + version_name = %[2]q + + data_access_role_arn = aws_iam_role.test.arn + + tags = { + %[3]q = %[4]q + } + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName, vName, key, value)) +} + +func testAccEntityRecognizerConfig_versionNameEmpty(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + version_name = "" + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_versionNameNotSet(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_versioNamePrefix(rName, versionNamePrefix string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + version_name_prefix = %[2]q + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName, versionNamePrefix)) +} + +func testAccEntityRecognizerConfig_testDocuments(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + test_s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_annotations_basic(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_annotations, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + annotations { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.annotations.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_annotations_testDocuments(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_annotations, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + test_s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + annotations { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.annotations.id}" + test_s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.annotations.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_annotations_noTestDocuments(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_annotations, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + annotations { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.annotations.id}" + test_s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.annotations.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_annotations_noTestAnnotations(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_annotations, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + test_s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + annotations { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.annotations.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_kmsKeyIds(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + model_kms_key_id = aws_kms_key.model.key_id + volume_kms_key_id = aws_kms_key.volume.key_id + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} + +resource "aws_iam_role_policy" "kms_keys" { + role = aws_iam_role.test.name + + policy = data.aws_iam_policy_document.kms_keys.json +} + +data "aws_iam_policy_document" "kms_keys" { + statement { + actions = [ + "*", + ] + + resources = [ + aws_kms_key.model.arn, + ] + } + statement { + actions = [ + "*", + ] + + resources = [ + aws_kms_key.volume.arn, + ] + } +} + +resource "aws_kms_key" "model" { + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "volume" { + deletion_window_in_days = 7 +} +`, rName)) +} + +func testAccEntityRecognizerConfig_kmsKeyARNs(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + model_kms_key_id = aws_kms_key.model.arn + volume_kms_key_id = aws_kms_key.volume.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} + +resource "aws_iam_role_policy" "kms_keys" { + role = aws_iam_role.test.name + + policy = data.aws_iam_policy_document.kms_keys.json +} + +data "aws_iam_policy_document" "kms_keys" { + statement { + actions = [ + "*", + ] + + resources = [ + aws_kms_key.model.arn, + ] + } + statement { + actions = [ + "*", + ] + + resources = [ + aws_kms_key.volume.arn, + ] + } +} + +resource "aws_kms_key" "model" { + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "volume" { + deletion_window_in_days = 7 +} +`, rName)) +} + +func testAccEntityRecognizerConfig_kmsKeys_None(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_kmsKeys_Set(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + model_kms_key_id = aws_kms_key.model.key_id + volume_kms_key_id = aws_kms_key.volume.key_id + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} + +resource "aws_iam_role_policy" "kms_keys" { + role = aws_iam_role.test.name + + policy = data.aws_iam_policy_document.kms_keys.json +} + +data "aws_iam_policy_document" "kms_keys" { + statement { + actions = [ + "*", + ] + + resources = [ + aws_kms_key.model.arn, + ] + } + statement { + actions = [ + "*", + ] + + resources = [ + aws_kms_key.volume.arn, + ] + } +} + +resource "aws_kms_key" "model" { + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "volume" { + deletion_window_in_days = 7 +} +`, rName)) +} + +func testAccEntityRecognizerConfig_kmsKeys_Update(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + model_kms_key_id = aws_kms_key.model2.key_id + volume_kms_key_id = aws_kms_key.volume2.key_id + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} + +resource "aws_iam_role_policy" "kms_keys" { + role = aws_iam_role.test.name + + policy = data.aws_iam_policy_document.kms_keys.json +} + +data "aws_iam_policy_document" "kms_keys" { + statement { + actions = [ + "*", + ] + + resources = [ + aws_kms_key.model2.arn, + ] + } + statement { + actions = [ + "*", + ] + + resources = [ + aws_kms_key.volume2.arn, + ] + } +} + +resource "aws_kms_key" "model2" { + deletion_window_in_days = 7 +} + +resource "aws_kms_key" "volume2" { + deletion_window_in_days = 7 +} +`, rName)) +} + +func testAccEntityRecognizerConfig_tags0(rName string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + tags = {} + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName)) +} + +func testAccEntityRecognizerConfig_tags1(rName, tagKey1, tagValue1 string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + tags = { + %[2]q = %[3]q + } + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName, tagKey1, tagValue1)) +} + +func testAccEntityRecognizerConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return acctest.ConfigCompose( + testAccEntityRecognizerBasicRoleConfig(rName), + testAccEntityRecognizerS3BucketConfig(rName), + testAccEntityRecognizerConfig_S3_entityList, + fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_comprehend_entity_recognizer" "test" { + name = %[1]q + + data_access_role_arn = aws_iam_role.test.arn + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } + + language_code = "en" + input_data_config { + entity_types { + type = "ENGINEER" + } + entity_types { + type = "MANAGER" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.test, + ] +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) +} + +func testAccEntityRecognizerS3BucketConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_s3_bucket_public_access_block" "test" { + bucket = aws_s3_bucket.test.bucket + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_ownership_controls" "test" { + bucket = aws_s3_bucket.test.bucket + + rule { + object_ownership = "BucketOwnerEnforced" + } +} +`, rName) +} + +func testAccEntityRecognizerBasicRoleConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = < 0 { + input := &comprehend.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: removedTags.IgnoreAWS().Keys(), + } + + _, err := conn.UntagResource(ctx, input) + + if err != nil { + return fmt.Errorf("untagging resource (%s): %w", identifier, err) + } + } + + if updatedTags := oldTags.Updated(newTags); len(updatedTags) > 0 { + input := &comprehend.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: Tags(updatedTags.IgnoreAWS()), + } + + _, err := conn.TagResource(ctx, input) + + if err != nil { + return fmt.Errorf("tagging resource (%s): %w", identifier, err) + } + } + + return nil +} diff --git a/internal/service/comprehend/test-fixtures/entity_recognizer/annotations.csv b/internal/service/comprehend/test-fixtures/entity_recognizer/annotations.csv new file mode 100644 index 00000000000..b60f915fc59 --- /dev/null +++ b/internal/service/comprehend/test-fixtures/entity_recognizer/annotations.csv @@ -0,0 +1,1001 @@ +File,Line,Begin Offset,End Offset,Type +documents.txt,0,19,32,MANAGER +documents.txt,1,0,15,MANAGER +documents.txt,2,0,22,MANAGER +documents.txt,3,0,14,MANAGER +documents.txt,4,0,13,ENGINEER +documents.txt,5,0,15,ENGINEER +documents.txt,6,0,14,ENGINEER +documents.txt,7,25,41,ENGINEER +documents.txt,8,0,19,MANAGER +documents.txt,9,25,38,MANAGER +documents.txt,10,0,16,MANAGER +documents.txt,11,0,12,ENGINEER +documents.txt,12,0,10,MANAGER +documents.txt,13,36,54,MANAGER +documents.txt,14,20,33,ENGINEER +documents.txt,15,0,22,MANAGER +documents.txt,16,0,14,MANAGER +documents.txt,17,0,21,MANAGER +documents.txt,18,0,15,MANAGER +documents.txt,19,0,15,MANAGER +documents.txt,20,0,14,MANAGER +documents.txt,21,20,35,ENGINEER +documents.txt,22,19,36,MANAGER +documents.txt,23,37,55,ENGINEER +documents.txt,24,0,12,MANAGER +documents.txt,25,0,12,MANAGER +documents.txt,26,19,36,MANAGER +documents.txt,27,0,13,ENGINEER +documents.txt,28,0,15,ENGINEER +documents.txt,29,0,15,MANAGER +documents.txt,30,0,17,MANAGER +documents.txt,31,0,13,MANAGER +documents.txt,32,0,13,ENGINEER +documents.txt,33,25,39,MANAGER +documents.txt,34,25,41,MANAGER +documents.txt,35,0,11,MANAGER +documents.txt,36,25,45,ENGINEER +documents.txt,37,0,15,MANAGER +documents.txt,38,0,12,MANAGER +documents.txt,39,0,14,ENGINEER +documents.txt,40,0,15,MANAGER +documents.txt,41,0,12,MANAGER +documents.txt,42,0,14,MANAGER +documents.txt,43,0,15,MANAGER +documents.txt,44,0,14,MANAGER +documents.txt,45,37,55,ENGINEER +documents.txt,46,0,14,ENGINEER +documents.txt,47,0,12,ENGINEER +documents.txt,48,20,33,ENGINEER +documents.txt,49,25,37,MANAGER +documents.txt,50,0,15,MANAGER +documents.txt,51,0,12,MANAGER +documents.txt,52,25,40,MANAGER +documents.txt,53,0,15,ENGINEER +documents.txt,54,37,51,ENGINEER +documents.txt,55,0,18,ENGINEER +documents.txt,56,25,38,MANAGER +documents.txt,57,0,18,ENGINEER +documents.txt,58,0,11,MANAGER +documents.txt,59,0,18,MANAGER +documents.txt,60,0,13,ENGINEER +documents.txt,61,19,35,MANAGER +documents.txt,62,0,14,ENGINEER +documents.txt,63,0,13,MANAGER +documents.txt,64,0,13,MANAGER +documents.txt,65,20,42,ENGINEER +documents.txt,66,25,41,MANAGER +documents.txt,67,0,22,MANAGER +documents.txt,68,25,41,ENGINEER +documents.txt,69,20,38,ENGINEER +documents.txt,70,0,11,ENGINEER +documents.txt,71,37,52,ENGINEER +documents.txt,72,0,20,ENGINEER +documents.txt,73,25,39,ENGINEER +documents.txt,74,0,11,MANAGER +documents.txt,75,0,13,ENGINEER +documents.txt,76,37,53,ENGINEER +documents.txt,77,0,17,MANAGER +documents.txt,78,0,9,MANAGER +documents.txt,79,25,43,ENGINEER +documents.txt,80,19,35,MANAGER +documents.txt,81,0,14,ENGINEER +documents.txt,82,20,30,ENGINEER +documents.txt,83,0,17,ENGINEER +documents.txt,84,36,53,MANAGER +documents.txt,85,0,20,ENGINEER +documents.txt,86,0,11,MANAGER +documents.txt,87,0,16,ENGINEER +documents.txt,88,19,35,MANAGER +documents.txt,89,0,18,MANAGER +documents.txt,90,0,12,ENGINEER +documents.txt,91,20,31,ENGINEER +documents.txt,92,20,31,ENGINEER +documents.txt,93,0,18,ENGINEER +documents.txt,94,0,13,MANAGER +documents.txt,95,25,38,MANAGER +documents.txt,96,0,18,MANAGER +documents.txt,97,37,48,ENGINEER +documents.txt,98,0,17,MANAGER +documents.txt,99,0,18,ENGINEER +documents.txt,100,0,10,MANAGER +documents.txt,101,0,15,MANAGER +documents.txt,102,0,21,ENGINEER +documents.txt,103,0,14,MANAGER +documents.txt,104,0,15,MANAGER +documents.txt,105,20,35,ENGINEER +documents.txt,106,0,16,MANAGER +documents.txt,107,0,14,ENGINEER +documents.txt,108,0,17,MANAGER +documents.txt,109,0,13,MANAGER +documents.txt,110,0,23,MANAGER +documents.txt,111,0,17,MANAGER +documents.txt,112,0,24,MANAGER +documents.txt,113,37,58,ENGINEER +documents.txt,114,0,12,ENGINEER +documents.txt,115,0,11,ENGINEER +documents.txt,116,0,14,ENGINEER +documents.txt,117,36,48,MANAGER +documents.txt,118,0,13,ENGINEER +documents.txt,119,0,13,ENGINEER +documents.txt,120,20,33,ENGINEER +documents.txt,121,0,15,MANAGER +documents.txt,122,0,19,ENGINEER +documents.txt,123,0,13,MANAGER +documents.txt,124,0,17,MANAGER +documents.txt,125,0,12,ENGINEER +documents.txt,126,0,16,MANAGER +documents.txt,127,25,42,MANAGER +documents.txt,128,25,36,ENGINEER +documents.txt,129,0,11,ENGINEER +documents.txt,130,0,15,ENGINEER +documents.txt,131,19,33,MANAGER +documents.txt,132,0,20,MANAGER +documents.txt,133,0,18,ENGINEER +documents.txt,134,37,49,ENGINEER +documents.txt,135,37,49,ENGINEER +documents.txt,136,20,37,ENGINEER +documents.txt,137,0,17,ENGINEER +documents.txt,138,0,17,ENGINEER +documents.txt,139,0,13,ENGINEER +documents.txt,140,37,57,ENGINEER +documents.txt,141,0,9,ENGINEER +documents.txt,142,0,12,MANAGER +documents.txt,143,0,10,MANAGER +documents.txt,144,0,16,MANAGER +documents.txt,145,19,30,MANAGER +documents.txt,146,19,37,MANAGER +documents.txt,147,0,12,MANAGER +documents.txt,148,0,18,MANAGER +documents.txt,149,0,12,MANAGER +documents.txt,150,0,10,ENGINEER +documents.txt,151,0,11,ENGINEER +documents.txt,152,37,48,ENGINEER +documents.txt,153,25,36,MANAGER +documents.txt,154,0,11,ENGINEER +documents.txt,155,20,35,ENGINEER +documents.txt,156,0,13,ENGINEER +documents.txt,157,0,14,MANAGER +documents.txt,158,0,18,MANAGER +documents.txt,159,0,18,MANAGER +documents.txt,160,20,34,ENGINEER +documents.txt,161,25,42,MANAGER +documents.txt,162,36,52,MANAGER +documents.txt,163,0,13,ENGINEER +documents.txt,164,0,15,MANAGER +documents.txt,165,0,12,ENGINEER +documents.txt,166,0,11,MANAGER +documents.txt,167,0,17,MANAGER +documents.txt,168,0,13,MANAGER +documents.txt,169,0,14,MANAGER +documents.txt,170,0,15,MANAGER +documents.txt,171,25,39,ENGINEER +documents.txt,172,0,17,MANAGER +documents.txt,173,0,13,MANAGER +documents.txt,174,0,14,ENGINEER +documents.txt,175,0,9,MANAGER +documents.txt,176,0,16,MANAGER +documents.txt,177,20,40,ENGINEER +documents.txt,178,0,14,ENGINEER +documents.txt,179,0,15,MANAGER +documents.txt,180,0,14,ENGINEER +documents.txt,181,0,13,MANAGER +documents.txt,182,20,36,ENGINEER +documents.txt,183,0,22,MANAGER +documents.txt,184,0,18,ENGINEER +documents.txt,185,0,17,MANAGER +documents.txt,186,0,13,MANAGER +documents.txt,187,0,15,MANAGER +documents.txt,188,36,47,MANAGER +documents.txt,189,0,20,ENGINEER +documents.txt,190,0,14,MANAGER +documents.txt,191,0,15,ENGINEER +documents.txt,192,0,18,MANAGER +documents.txt,193,0,10,MANAGER +documents.txt,194,0,18,ENGINEER +documents.txt,195,0,12,ENGINEER +documents.txt,196,25,37,MANAGER +documents.txt,197,0,10,ENGINEER +documents.txt,198,0,9,MANAGER +documents.txt,199,0,12,ENGINEER +documents.txt,200,0,16,ENGINEER +documents.txt,201,0,14,ENGINEER +documents.txt,202,0,16,MANAGER +documents.txt,203,37,53,ENGINEER +documents.txt,204,0,17,MANAGER +documents.txt,205,0,14,ENGINEER +documents.txt,206,25,45,MANAGER +documents.txt,207,0,15,MANAGER +documents.txt,208,25,42,MANAGER +documents.txt,209,19,36,MANAGER +documents.txt,210,0,15,MANAGER +documents.txt,211,0,11,MANAGER +documents.txt,212,0,12,MANAGER +documents.txt,213,36,50,MANAGER +documents.txt,214,20,43,ENGINEER +documents.txt,215,0,17,MANAGER +documents.txt,216,0,13,MANAGER +documents.txt,217,0,14,MANAGER +documents.txt,218,0,12,ENGINEER +documents.txt,219,0,13,ENGINEER +documents.txt,220,20,34,ENGINEER +documents.txt,221,0,16,ENGINEER +documents.txt,222,25,40,MANAGER +documents.txt,223,25,42,ENGINEER +documents.txt,224,25,38,MANAGER +documents.txt,225,0,14,MANAGER +documents.txt,226,0,11,MANAGER +documents.txt,227,0,12,MANAGER +documents.txt,228,0,22,ENGINEER +documents.txt,229,0,12,ENGINEER +documents.txt,230,0,15,ENGINEER +documents.txt,231,25,42,MANAGER +documents.txt,232,0,12,ENGINEER +documents.txt,233,0,11,MANAGER +documents.txt,234,36,48,MANAGER +documents.txt,235,0,14,ENGINEER +documents.txt,236,36,49,MANAGER +documents.txt,237,36,55,MANAGER +documents.txt,238,20,38,ENGINEER +documents.txt,239,0,10,ENGINEER +documents.txt,240,0,10,MANAGER +documents.txt,241,0,15,MANAGER +documents.txt,242,0,16,ENGINEER +documents.txt,243,0,15,ENGINEER +documents.txt,244,0,12,ENGINEER +documents.txt,245,0,11,ENGINEER +documents.txt,246,0,15,MANAGER +documents.txt,247,0,13,MANAGER +documents.txt,248,0,12,ENGINEER +documents.txt,249,0,14,ENGINEER +documents.txt,250,25,37,MANAGER +documents.txt,251,25,36,MANAGER +documents.txt,252,0,12,MANAGER +documents.txt,253,25,40,MANAGER +documents.txt,254,25,39,MANAGER +documents.txt,255,0,17,MANAGER +documents.txt,256,0,18,MANAGER +documents.txt,257,36,50,MANAGER +documents.txt,258,37,52,ENGINEER +documents.txt,259,0,20,ENGINEER +documents.txt,260,0,15,ENGINEER +documents.txt,261,36,48,MANAGER +documents.txt,262,0,13,ENGINEER +documents.txt,263,0,15,MANAGER +documents.txt,264,0,16,MANAGER +documents.txt,265,0,16,ENGINEER +documents.txt,266,0,17,MANAGER +documents.txt,267,36,54,MANAGER +documents.txt,268,0,15,MANAGER +documents.txt,269,0,14,ENGINEER +documents.txt,270,0,18,MANAGER +documents.txt,271,0,11,MANAGER +documents.txt,272,0,21,ENGINEER +documents.txt,273,0,21,ENGINEER +documents.txt,274,0,14,ENGINEER +documents.txt,275,0,14,MANAGER +documents.txt,276,0,18,ENGINEER +documents.txt,277,0,16,ENGINEER +documents.txt,278,0,13,MANAGER +documents.txt,279,0,15,ENGINEER +documents.txt,280,0,13,MANAGER +documents.txt,281,0,18,MANAGER +documents.txt,282,0,8,MANAGER +documents.txt,283,0,12,ENGINEER +documents.txt,284,0,15,MANAGER +documents.txt,285,36,55,MANAGER +documents.txt,286,0,16,ENGINEER +documents.txt,287,25,40,MANAGER +documents.txt,288,19,33,MANAGER +documents.txt,289,0,14,ENGINEER +documents.txt,290,0,13,ENGINEER +documents.txt,291,19,33,MANAGER +documents.txt,292,0,13,MANAGER +documents.txt,293,25,37,ENGINEER +documents.txt,294,0,16,ENGINEER +documents.txt,295,0,25,ENGINEER +documents.txt,296,0,17,ENGINEER +documents.txt,297,37,52,ENGINEER +documents.txt,298,37,53,ENGINEER +documents.txt,299,0,13,MANAGER +documents.txt,300,20,39,ENGINEER +documents.txt,301,0,15,MANAGER +documents.txt,302,0,15,MANAGER +documents.txt,303,0,12,MANAGER +documents.txt,304,0,22,MANAGER +documents.txt,305,25,42,MANAGER +documents.txt,306,0,13,ENGINEER +documents.txt,307,25,43,MANAGER +documents.txt,308,37,55,ENGINEER +documents.txt,309,0,19,MANAGER +documents.txt,310,36,53,MANAGER +documents.txt,311,0,13,ENGINEER +documents.txt,312,0,12,ENGINEER +documents.txt,313,0,12,MANAGER +documents.txt,314,36,49,MANAGER +documents.txt,315,0,18,ENGINEER +documents.txt,316,0,14,ENGINEER +documents.txt,317,0,13,MANAGER +documents.txt,318,25,37,ENGINEER +documents.txt,319,37,49,ENGINEER +documents.txt,320,0,21,ENGINEER +documents.txt,321,0,11,MANAGER +documents.txt,322,0,14,ENGINEER +documents.txt,323,25,44,MANAGER +documents.txt,324,0,13,MANAGER +documents.txt,325,25,35,ENGINEER +documents.txt,326,25,41,MANAGER +documents.txt,327,0,12,ENGINEER +documents.txt,328,0,11,MANAGER +documents.txt,329,0,22,MANAGER +documents.txt,330,0,19,MANAGER +documents.txt,331,0,13,ENGINEER +documents.txt,332,0,15,MANAGER +documents.txt,333,0,13,MANAGER +documents.txt,334,0,13,ENGINEER +documents.txt,335,25,46,MANAGER +documents.txt,336,19,39,MANAGER +documents.txt,337,0,16,ENGINEER +documents.txt,338,0,12,ENGINEER +documents.txt,339,0,11,ENGINEER +documents.txt,340,20,34,ENGINEER +documents.txt,341,0,13,MANAGER +documents.txt,342,0,11,MANAGER +documents.txt,343,0,12,MANAGER +documents.txt,344,0,16,MANAGER +documents.txt,345,0,13,MANAGER +documents.txt,346,0,15,MANAGER +documents.txt,347,0,17,MANAGER +documents.txt,348,37,52,ENGINEER +documents.txt,349,0,12,MANAGER +documents.txt,350,36,50,MANAGER +documents.txt,351,0,12,ENGINEER +documents.txt,352,0,13,ENGINEER +documents.txt,353,0,11,MANAGER +documents.txt,354,36,49,MANAGER +documents.txt,355,0,13,ENGINEER +documents.txt,356,0,18,ENGINEER +documents.txt,357,37,55,ENGINEER +documents.txt,358,20,31,ENGINEER +documents.txt,359,0,20,ENGINEER +documents.txt,360,0,15,ENGINEER +documents.txt,361,0,14,MANAGER +documents.txt,362,0,13,MANAGER +documents.txt,363,19,34,MANAGER +documents.txt,364,0,12,MANAGER +documents.txt,365,0,13,MANAGER +documents.txt,366,0,14,MANAGER +documents.txt,367,0,17,ENGINEER +documents.txt,368,0,13,MANAGER +documents.txt,369,0,17,ENGINEER +documents.txt,370,37,50,ENGINEER +documents.txt,371,0,19,MANAGER +documents.txt,372,25,42,ENGINEER +documents.txt,373,0,14,MANAGER +documents.txt,374,25,38,ENGINEER +documents.txt,375,0,13,ENGINEER +documents.txt,376,0,11,MANAGER +documents.txt,377,0,12,ENGINEER +documents.txt,378,25,40,MANAGER +documents.txt,379,0,15,ENGINEER +documents.txt,380,0,11,ENGINEER +documents.txt,381,0,20,MANAGER +documents.txt,382,0,19,ENGINEER +documents.txt,383,0,24,ENGINEER +documents.txt,384,0,12,ENGINEER +documents.txt,385,0,16,MANAGER +documents.txt,386,0,14,MANAGER +documents.txt,387,0,9,MANAGER +documents.txt,388,0,12,MANAGER +documents.txt,389,36,50,MANAGER +documents.txt,390,20,32,ENGINEER +documents.txt,391,0,15,ENGINEER +documents.txt,392,0,17,MANAGER +documents.txt,393,19,34,MANAGER +documents.txt,394,0,17,ENGINEER +documents.txt,395,0,16,ENGINEER +documents.txt,396,0,16,MANAGER +documents.txt,397,0,20,ENGINEER +documents.txt,398,0,17,MANAGER +documents.txt,399,0,16,MANAGER +documents.txt,400,0,12,ENGINEER +documents.txt,401,0,10,MANAGER +documents.txt,402,0,14,MANAGER +documents.txt,403,0,11,ENGINEER +documents.txt,404,25,35,ENGINEER +documents.txt,405,0,13,ENGINEER +documents.txt,406,0,13,MANAGER +documents.txt,407,36,47,MANAGER +documents.txt,408,20,31,ENGINEER +documents.txt,409,37,47,ENGINEER +documents.txt,410,0,13,ENGINEER +documents.txt,411,20,34,ENGINEER +documents.txt,412,0,19,MANAGER +documents.txt,413,0,12,ENGINEER +documents.txt,414,0,14,ENGINEER +documents.txt,415,0,14,MANAGER +documents.txt,416,20,31,ENGINEER +documents.txt,417,0,13,MANAGER +documents.txt,418,0,17,ENGINEER +documents.txt,419,0,12,ENGINEER +documents.txt,420,0,13,ENGINEER +documents.txt,421,0,15,MANAGER +documents.txt,422,19,37,MANAGER +documents.txt,423,37,50,ENGINEER +documents.txt,424,0,17,MANAGER +documents.txt,425,0,15,ENGINEER +documents.txt,426,0,9,ENGINEER +documents.txt,427,0,11,MANAGER +documents.txt,428,0,13,MANAGER +documents.txt,429,0,13,MANAGER +documents.txt,430,0,17,ENGINEER +documents.txt,431,20,39,ENGINEER +documents.txt,432,19,32,MANAGER +documents.txt,433,0,19,MANAGER +documents.txt,434,25,40,ENGINEER +documents.txt,435,0,14,MANAGER +documents.txt,436,0,16,ENGINEER +documents.txt,437,0,24,ENGINEER +documents.txt,438,19,38,MANAGER +documents.txt,439,0,17,MANAGER +documents.txt,440,36,52,MANAGER +documents.txt,441,0,16,ENGINEER +documents.txt,442,0,20,MANAGER +documents.txt,443,0,11,MANAGER +documents.txt,444,0,12,MANAGER +documents.txt,445,0,16,MANAGER +documents.txt,446,0,13,MANAGER +documents.txt,447,0,15,MANAGER +documents.txt,448,0,14,ENGINEER +documents.txt,449,0,17,ENGINEER +documents.txt,450,0,13,MANAGER +documents.txt,451,0,14,ENGINEER +documents.txt,452,0,12,MANAGER +documents.txt,453,0,9,MANAGER +documents.txt,454,0,18,MANAGER +documents.txt,455,25,42,ENGINEER +documents.txt,456,0,20,MANAGER +documents.txt,457,0,15,ENGINEER +documents.txt,458,37,47,ENGINEER +documents.txt,459,0,23,ENGINEER +documents.txt,460,0,13,MANAGER +documents.txt,461,19,35,MANAGER +documents.txt,462,0,10,ENGINEER +documents.txt,463,0,15,MANAGER +documents.txt,464,0,12,MANAGER +documents.txt,465,0,11,MANAGER +documents.txt,466,25,38,ENGINEER +documents.txt,467,25,41,MANAGER +documents.txt,468,25,44,MANAGER +documents.txt,469,25,41,MANAGER +documents.txt,470,0,18,MANAGER +documents.txt,471,0,10,ENGINEER +documents.txt,472,0,15,ENGINEER +documents.txt,473,0,17,MANAGER +documents.txt,474,19,40,MANAGER +documents.txt,475,0,15,ENGINEER +documents.txt,476,19,35,MANAGER +documents.txt,477,0,14,MANAGER +documents.txt,478,0,18,MANAGER +documents.txt,479,0,15,ENGINEER +documents.txt,480,25,47,MANAGER +documents.txt,481,20,32,ENGINEER +documents.txt,482,0,13,ENGINEER +documents.txt,483,0,24,ENGINEER +documents.txt,484,0,16,ENGINEER +documents.txt,485,0,13,MANAGER +documents.txt,486,0,20,MANAGER +documents.txt,487,0,15,MANAGER +documents.txt,488,0,15,ENGINEER +documents.txt,489,0,11,ENGINEER +documents.txt,490,0,10,MANAGER +documents.txt,491,25,38,ENGINEER +documents.txt,492,0,12,ENGINEER +documents.txt,493,0,15,MANAGER +documents.txt,494,0,12,MANAGER +documents.txt,495,0,11,ENGINEER +documents.txt,496,0,15,MANAGER +documents.txt,497,0,15,ENGINEER +documents.txt,498,25,41,ENGINEER +documents.txt,499,25,38,ENGINEER +documents.txt,500,0,14,MANAGER +documents.txt,501,25,37,MANAGER +documents.txt,502,0,14,MANAGER +documents.txt,503,25,40,ENGINEER +documents.txt,504,0,10,ENGINEER +documents.txt,505,0,17,MANAGER +documents.txt,506,0,16,MANAGER +documents.txt,507,0,10,ENGINEER +documents.txt,508,0,12,MANAGER +documents.txt,509,0,13,ENGINEER +documents.txt,510,0,12,ENGINEER +documents.txt,511,25,38,ENGINEER +documents.txt,512,0,10,MANAGER +documents.txt,513,0,13,MANAGER +documents.txt,514,0,14,ENGINEER +documents.txt,515,0,15,MANAGER +documents.txt,516,0,17,MANAGER +documents.txt,517,20,32,ENGINEER +documents.txt,518,0,15,ENGINEER +documents.txt,519,0,14,ENGINEER +documents.txt,520,19,39,MANAGER +documents.txt,521,0,15,MANAGER +documents.txt,522,0,17,ENGINEER +documents.txt,523,0,15,ENGINEER +documents.txt,524,0,17,MANAGER +documents.txt,525,0,12,MANAGER +documents.txt,526,0,11,MANAGER +documents.txt,527,20,32,ENGINEER +documents.txt,528,0,16,ENGINEER +documents.txt,529,0,18,ENGINEER +documents.txt,530,20,35,ENGINEER +documents.txt,531,0,14,ENGINEER +documents.txt,532,0,18,MANAGER +documents.txt,533,0,16,ENGINEER +documents.txt,534,0,8,ENGINEER +documents.txt,535,0,14,MANAGER +documents.txt,536,25,47,ENGINEER +documents.txt,537,0,16,ENGINEER +documents.txt,538,20,34,ENGINEER +documents.txt,539,0,14,MANAGER +documents.txt,540,0,11,MANAGER +documents.txt,541,25,37,MANAGER +documents.txt,542,0,13,MANAGER +documents.txt,543,0,16,ENGINEER +documents.txt,544,0,10,MANAGER +documents.txt,545,0,16,ENGINEER +documents.txt,546,0,17,MANAGER +documents.txt,547,25,42,MANAGER +documents.txt,548,0,12,MANAGER +documents.txt,549,0,17,MANAGER +documents.txt,550,0,12,ENGINEER +documents.txt,551,0,19,MANAGER +documents.txt,552,0,15,ENGINEER +documents.txt,553,0,16,MANAGER +documents.txt,554,20,35,ENGINEER +documents.txt,555,0,20,MANAGER +documents.txt,556,0,15,MANAGER +documents.txt,557,0,15,MANAGER +documents.txt,558,0,17,MANAGER +documents.txt,559,0,17,ENGINEER +documents.txt,560,19,33,MANAGER +documents.txt,561,36,44,MANAGER +documents.txt,562,0,13,MANAGER +documents.txt,563,0,15,MANAGER +documents.txt,564,0,13,MANAGER +documents.txt,565,0,21,ENGINEER +documents.txt,566,0,22,ENGINEER +documents.txt,567,19,36,MANAGER +documents.txt,568,20,33,ENGINEER +documents.txt,569,0,14,MANAGER +documents.txt,570,0,16,ENGINEER +documents.txt,571,0,13,ENGINEER +documents.txt,572,0,18,ENGINEER +documents.txt,573,0,10,ENGINEER +documents.txt,574,0,13,MANAGER +documents.txt,575,0,15,MANAGER +documents.txt,576,0,17,ENGINEER +documents.txt,577,0,17,ENGINEER +documents.txt,578,0,14,ENGINEER +documents.txt,579,0,13,MANAGER +documents.txt,580,0,17,ENGINEER +documents.txt,581,37,48,ENGINEER +documents.txt,582,0,16,ENGINEER +documents.txt,583,37,55,ENGINEER +documents.txt,584,0,11,MANAGER +documents.txt,585,37,55,ENGINEER +documents.txt,586,0,20,MANAGER +documents.txt,587,0,13,MANAGER +documents.txt,588,0,13,MANAGER +documents.txt,589,25,35,ENGINEER +documents.txt,590,0,15,ENGINEER +documents.txt,591,0,21,MANAGER +documents.txt,592,0,13,MANAGER +documents.txt,593,0,12,ENGINEER +documents.txt,594,0,16,ENGINEER +documents.txt,595,20,34,ENGINEER +documents.txt,596,20,34,ENGINEER +documents.txt,597,0,14,ENGINEER +documents.txt,598,0,17,MANAGER +documents.txt,599,0,13,MANAGER +documents.txt,600,0,20,MANAGER +documents.txt,601,0,16,MANAGER +documents.txt,602,0,18,MANAGER +documents.txt,603,0,18,MANAGER +documents.txt,604,0,19,MANAGER +documents.txt,605,0,19,MANAGER +documents.txt,606,0,12,ENGINEER +documents.txt,607,25,43,ENGINEER +documents.txt,608,0,22,MANAGER +documents.txt,609,0,12,MANAGER +documents.txt,610,36,53,MANAGER +documents.txt,611,0,12,ENGINEER +documents.txt,612,0,16,MANAGER +documents.txt,613,0,14,MANAGER +documents.txt,614,0,13,ENGINEER +documents.txt,615,0,17,ENGINEER +documents.txt,616,25,39,ENGINEER +documents.txt,617,0,13,ENGINEER +documents.txt,618,0,19,ENGINEER +documents.txt,619,0,15,MANAGER +documents.txt,620,0,20,MANAGER +documents.txt,621,0,15,MANAGER +documents.txt,622,0,14,ENGINEER +documents.txt,623,0,15,MANAGER +documents.txt,624,37,51,ENGINEER +documents.txt,625,0,19,ENGINEER +documents.txt,626,0,19,ENGINEER +documents.txt,627,0,13,MANAGER +documents.txt,628,0,17,MANAGER +documents.txt,629,0,22,MANAGER +documents.txt,630,0,14,ENGINEER +documents.txt,631,0,21,ENGINEER +documents.txt,632,0,12,ENGINEER +documents.txt,633,0,16,ENGINEER +documents.txt,634,0,13,ENGINEER +documents.txt,635,36,49,MANAGER +documents.txt,636,0,10,MANAGER +documents.txt,637,0,24,MANAGER +documents.txt,638,19,36,MANAGER +documents.txt,639,0,18,ENGINEER +documents.txt,640,0,15,MANAGER +documents.txt,641,0,19,ENGINEER +documents.txt,642,0,17,ENGINEER +documents.txt,643,0,13,ENGINEER +documents.txt,644,0,18,ENGINEER +documents.txt,645,0,17,ENGINEER +documents.txt,646,19,29,MANAGER +documents.txt,647,0,14,ENGINEER +documents.txt,648,0,16,MANAGER +documents.txt,649,0,14,MANAGER +documents.txt,650,0,14,MANAGER +documents.txt,651,0,19,MANAGER +documents.txt,652,0,10,ENGINEER +documents.txt,653,0,18,MANAGER +documents.txt,654,0,16,ENGINEER +documents.txt,655,0,12,MANAGER +documents.txt,656,0,20,ENGINEER +documents.txt,657,19,40,MANAGER +documents.txt,658,0,12,MANAGER +documents.txt,659,0,20,MANAGER +documents.txt,660,25,39,MANAGER +documents.txt,661,0,18,MANAGER +documents.txt,662,0,16,ENGINEER +documents.txt,663,25,33,MANAGER +documents.txt,664,0,10,MANAGER +documents.txt,665,25,38,ENGINEER +documents.txt,666,0,11,MANAGER +documents.txt,667,0,17,ENGINEER +documents.txt,668,36,55,MANAGER +documents.txt,669,0,11,MANAGER +documents.txt,670,0,18,ENGINEER +documents.txt,671,0,13,ENGINEER +documents.txt,672,25,45,MANAGER +documents.txt,673,0,13,MANAGER +documents.txt,674,0,16,MANAGER +documents.txt,675,0,18,ENGINEER +documents.txt,676,0,13,ENGINEER +documents.txt,677,37,56,ENGINEER +documents.txt,678,0,16,MANAGER +documents.txt,679,0,18,MANAGER +documents.txt,680,0,17,MANAGER +documents.txt,681,25,39,MANAGER +documents.txt,682,0,14,MANAGER +documents.txt,683,0,11,MANAGER +documents.txt,684,0,12,ENGINEER +documents.txt,685,0,20,ENGINEER +documents.txt,686,0,16,MANAGER +documents.txt,687,0,11,ENGINEER +documents.txt,688,0,9,ENGINEER +documents.txt,689,0,18,ENGINEER +documents.txt,690,0,16,MANAGER +documents.txt,691,0,15,ENGINEER +documents.txt,692,0,14,ENGINEER +documents.txt,693,0,16,ENGINEER +documents.txt,694,0,14,MANAGER +documents.txt,695,0,12,MANAGER +documents.txt,696,0,15,ENGINEER +documents.txt,697,0,8,ENGINEER +documents.txt,698,0,11,MANAGER +documents.txt,699,0,19,ENGINEER +documents.txt,700,25,41,MANAGER +documents.txt,701,0,14,MANAGER +documents.txt,702,0,13,ENGINEER +documents.txt,703,0,15,MANAGER +documents.txt,704,25,39,ENGINEER +documents.txt,705,0,10,MANAGER +documents.txt,706,0,15,MANAGER +documents.txt,707,25,36,ENGINEER +documents.txt,708,0,14,MANAGER +documents.txt,709,0,12,MANAGER +documents.txt,710,0,14,ENGINEER +documents.txt,711,36,45,MANAGER +documents.txt,712,0,15,MANAGER +documents.txt,713,0,13,ENGINEER +documents.txt,714,25,37,MANAGER +documents.txt,715,0,10,ENGINEER +documents.txt,716,0,12,MANAGER +documents.txt,717,0,12,MANAGER +documents.txt,718,0,17,ENGINEER +documents.txt,719,19,34,MANAGER +documents.txt,720,0,16,ENGINEER +documents.txt,721,0,18,ENGINEER +documents.txt,722,0,16,MANAGER +documents.txt,723,37,56,ENGINEER +documents.txt,724,36,56,MANAGER +documents.txt,725,0,17,ENGINEER +documents.txt,726,0,21,MANAGER +documents.txt,727,0,13,ENGINEER +documents.txt,728,0,14,ENGINEER +documents.txt,729,0,11,MANAGER +documents.txt,730,0,13,MANAGER +documents.txt,731,0,16,ENGINEER +documents.txt,732,0,17,MANAGER +documents.txt,733,25,39,MANAGER +documents.txt,734,0,17,MANAGER +documents.txt,735,36,48,MANAGER +documents.txt,736,0,11,MANAGER +documents.txt,737,0,16,MANAGER +documents.txt,738,0,16,ENGINEER +documents.txt,739,0,16,MANAGER +documents.txt,740,0,14,MANAGER +documents.txt,741,0,16,ENGINEER +documents.txt,742,0,17,ENGINEER +documents.txt,743,25,44,ENGINEER +documents.txt,744,25,38,ENGINEER +documents.txt,745,0,14,ENGINEER +documents.txt,746,19,32,MANAGER +documents.txt,747,0,11,ENGINEER +documents.txt,748,0,21,ENGINEER +documents.txt,749,0,16,ENGINEER +documents.txt,750,0,18,ENGINEER +documents.txt,751,0,11,MANAGER +documents.txt,752,0,10,ENGINEER +documents.txt,753,0,14,ENGINEER +documents.txt,754,0,17,MANAGER +documents.txt,755,0,16,ENGINEER +documents.txt,756,0,13,MANAGER +documents.txt,757,0,18,ENGINEER +documents.txt,758,0,15,MANAGER +documents.txt,759,0,13,ENGINEER +documents.txt,760,0,10,MANAGER +documents.txt,761,0,14,ENGINEER +documents.txt,762,25,39,MANAGER +documents.txt,763,37,54,ENGINEER +documents.txt,764,0,12,MANAGER +documents.txt,765,0,14,MANAGER +documents.txt,766,0,19,MANAGER +documents.txt,767,0,18,MANAGER +documents.txt,768,20,37,ENGINEER +documents.txt,769,0,14,MANAGER +documents.txt,770,25,38,MANAGER +documents.txt,771,0,15,ENGINEER +documents.txt,772,0,13,ENGINEER +documents.txt,773,0,14,MANAGER +documents.txt,774,25,39,MANAGER +documents.txt,775,0,18,MANAGER +documents.txt,776,0,17,MANAGER +documents.txt,777,0,14,MANAGER +documents.txt,778,19,33,MANAGER +documents.txt,779,0,16,MANAGER +documents.txt,780,0,10,ENGINEER +documents.txt,781,0,11,ENGINEER +documents.txt,782,20,37,ENGINEER +documents.txt,783,37,49,ENGINEER +documents.txt,784,0,14,ENGINEER +documents.txt,785,0,10,ENGINEER +documents.txt,786,36,48,MANAGER +documents.txt,787,19,30,MANAGER +documents.txt,788,0,14,ENGINEER +documents.txt,789,0,16,MANAGER +documents.txt,790,0,23,ENGINEER +documents.txt,791,25,38,MANAGER +documents.txt,792,37,53,ENGINEER +documents.txt,793,0,12,ENGINEER +documents.txt,794,36,51,MANAGER +documents.txt,795,0,17,MANAGER +documents.txt,796,0,17,ENGINEER +documents.txt,797,0,18,ENGINEER +documents.txt,798,0,15,MANAGER +documents.txt,799,0,11,ENGINEER +documents.txt,800,0,14,MANAGER +documents.txt,801,0,12,ENGINEER +documents.txt,802,0,11,ENGINEER +documents.txt,803,0,15,MANAGER +documents.txt,804,0,13,ENGINEER +documents.txt,805,0,14,MANAGER +documents.txt,806,20,35,ENGINEER +documents.txt,807,25,36,ENGINEER +documents.txt,808,0,15,MANAGER +documents.txt,809,0,12,ENGINEER +documents.txt,810,37,51,ENGINEER +documents.txt,811,0,10,ENGINEER +documents.txt,812,0,12,MANAGER +documents.txt,813,20,31,ENGINEER +documents.txt,814,0,17,ENGINEER +documents.txt,815,0,10,ENGINEER +documents.txt,816,19,32,MANAGER +documents.txt,817,0,16,MANAGER +documents.txt,818,0,11,MANAGER +documents.txt,819,0,14,ENGINEER +documents.txt,820,0,19,MANAGER +documents.txt,821,0,13,ENGINEER +documents.txt,822,0,16,MANAGER +documents.txt,823,0,14,MANAGER +documents.txt,824,0,14,MANAGER +documents.txt,825,0,13,ENGINEER +documents.txt,826,0,14,ENGINEER +documents.txt,827,0,10,ENGINEER +documents.txt,828,0,11,MANAGER +documents.txt,829,0,15,ENGINEER +documents.txt,830,0,10,MANAGER +documents.txt,831,0,17,MANAGER +documents.txt,832,0,19,MANAGER +documents.txt,833,0,15,ENGINEER +documents.txt,834,0,20,ENGINEER +documents.txt,835,0,15,MANAGER +documents.txt,836,0,16,MANAGER +documents.txt,837,0,11,MANAGER +documents.txt,838,0,13,MANAGER +documents.txt,839,0,14,MANAGER +documents.txt,840,0,15,ENGINEER +documents.txt,841,0,16,MANAGER +documents.txt,842,25,43,ENGINEER +documents.txt,843,0,17,MANAGER +documents.txt,844,0,15,ENGINEER +documents.txt,845,0,14,MANAGER +documents.txt,846,0,16,ENGINEER +documents.txt,847,0,10,ENGINEER +documents.txt,848,0,11,ENGINEER +documents.txt,849,36,53,MANAGER +documents.txt,850,0,21,MANAGER +documents.txt,851,0,15,MANAGER +documents.txt,852,0,13,MANAGER +documents.txt,853,0,11,ENGINEER +documents.txt,854,0,22,MANAGER +documents.txt,855,0,13,MANAGER +documents.txt,856,0,12,MANAGER +documents.txt,857,0,16,ENGINEER +documents.txt,858,0,18,ENGINEER +documents.txt,859,0,9,ENGINEER +documents.txt,860,0,12,ENGINEER +documents.txt,861,0,14,ENGINEER +documents.txt,862,37,55,ENGINEER +documents.txt,863,0,12,MANAGER +documents.txt,864,0,15,ENGINEER +documents.txt,865,0,13,ENGINEER +documents.txt,866,0,14,ENGINEER +documents.txt,867,20,32,ENGINEER +documents.txt,868,37,50,ENGINEER +documents.txt,869,0,10,ENGINEER +documents.txt,870,0,13,MANAGER +documents.txt,871,0,16,ENGINEER +documents.txt,872,0,14,ENGINEER +documents.txt,873,0,16,MANAGER +documents.txt,874,25,40,ENGINEER +documents.txt,875,0,14,ENGINEER +documents.txt,876,36,49,MANAGER +documents.txt,877,0,9,MANAGER +documents.txt,878,0,17,MANAGER +documents.txt,879,25,39,MANAGER +documents.txt,880,0,14,MANAGER +documents.txt,881,37,57,ENGINEER +documents.txt,882,0,12,MANAGER +documents.txt,883,19,34,MANAGER +documents.txt,884,0,18,ENGINEER +documents.txt,885,0,16,ENGINEER +documents.txt,886,37,50,ENGINEER +documents.txt,887,0,20,ENGINEER +documents.txt,888,0,16,ENGINEER +documents.txt,889,0,19,MANAGER +documents.txt,890,0,11,MANAGER +documents.txt,891,0,10,MANAGER +documents.txt,892,0,17,ENGINEER +documents.txt,893,0,19,ENGINEER +documents.txt,894,0,9,MANAGER +documents.txt,895,0,14,ENGINEER +documents.txt,896,0,14,MANAGER +documents.txt,897,0,10,ENGINEER +documents.txt,898,0,20,ENGINEER +documents.txt,899,0,13,ENGINEER +documents.txt,900,0,24,ENGINEER +documents.txt,901,0,11,MANAGER +documents.txt,902,0,18,ENGINEER +documents.txt,903,0,19,MANAGER +documents.txt,904,37,52,ENGINEER +documents.txt,905,0,17,MANAGER +documents.txt,906,0,14,ENGINEER +documents.txt,907,0,13,MANAGER +documents.txt,908,0,16,ENGINEER +documents.txt,909,0,13,ENGINEER +documents.txt,910,0,11,ENGINEER +documents.txt,911,0,12,ENGINEER +documents.txt,912,0,16,ENGINEER +documents.txt,913,0,12,ENGINEER +documents.txt,914,36,50,MANAGER +documents.txt,915,0,15,ENGINEER +documents.txt,916,0,16,ENGINEER +documents.txt,917,36,50,MANAGER +documents.txt,918,0,12,MANAGER +documents.txt,919,0,14,ENGINEER +documents.txt,920,0,15,MANAGER +documents.txt,921,0,13,ENGINEER +documents.txt,922,20,36,ENGINEER +documents.txt,923,0,18,ENGINEER +documents.txt,924,19,37,MANAGER +documents.txt,925,0,16,ENGINEER +documents.txt,926,0,14,ENGINEER +documents.txt,927,25,36,ENGINEER +documents.txt,928,37,49,ENGINEER +documents.txt,929,0,10,MANAGER +documents.txt,930,0,10,ENGINEER +documents.txt,931,0,14,ENGINEER +documents.txt,932,0,15,ENGINEER +documents.txt,933,0,16,MANAGER +documents.txt,934,0,14,ENGINEER +documents.txt,935,0,23,ENGINEER +documents.txt,936,0,18,ENGINEER +documents.txt,937,0,18,MANAGER +documents.txt,938,0,16,ENGINEER +documents.txt,939,36,49,MANAGER +documents.txt,940,0,15,ENGINEER +documents.txt,941,0,13,ENGINEER +documents.txt,942,0,13,MANAGER +documents.txt,943,25,39,ENGINEER +documents.txt,944,37,54,ENGINEER +documents.txt,945,0,12,MANAGER +documents.txt,946,0,13,ENGINEER +documents.txt,947,0,18,MANAGER +documents.txt,948,20,36,ENGINEER +documents.txt,949,0,11,ENGINEER +documents.txt,950,0,14,ENGINEER +documents.txt,951,0,15,ENGINEER +documents.txt,952,0,16,MANAGER +documents.txt,953,0,10,ENGINEER +documents.txt,954,0,18,ENGINEER +documents.txt,955,0,15,MANAGER +documents.txt,956,25,37,MANAGER +documents.txt,957,0,15,ENGINEER +documents.txt,958,0,10,MANAGER +documents.txt,959,0,14,ENGINEER +documents.txt,960,0,18,ENGINEER +documents.txt,961,0,14,MANAGER +documents.txt,962,0,14,MANAGER +documents.txt,963,0,14,MANAGER +documents.txt,964,0,12,ENGINEER +documents.txt,965,0,19,MANAGER +documents.txt,966,0,17,ENGINEER +documents.txt,967,0,12,ENGINEER +documents.txt,968,0,15,MANAGER +documents.txt,969,0,17,ENGINEER +documents.txt,970,0,11,MANAGER +documents.txt,971,25,39,ENGINEER +documents.txt,972,0,12,ENGINEER +documents.txt,973,19,33,MANAGER +documents.txt,974,19,32,MANAGER +documents.txt,975,0,23,MANAGER +documents.txt,976,20,44,ENGINEER +documents.txt,977,0,13,ENGINEER +documents.txt,978,0,15,MANAGER +documents.txt,979,0,19,ENGINEER +documents.txt,980,0,12,MANAGER +documents.txt,981,25,40,MANAGER +documents.txt,982,0,12,ENGINEER +documents.txt,983,0,13,MANAGER +documents.txt,984,0,12,MANAGER +documents.txt,985,37,53,ENGINEER +documents.txt,986,25,38,ENGINEER +documents.txt,987,0,11,ENGINEER +documents.txt,988,37,50,ENGINEER +documents.txt,989,0,18,ENGINEER +documents.txt,990,20,35,ENGINEER +documents.txt,991,19,33,MANAGER +documents.txt,992,0,18,MANAGER +documents.txt,993,0,17,MANAGER +documents.txt,994,0,11,MANAGER +documents.txt,995,0,13,MANAGER +documents.txt,996,0,14,MANAGER +documents.txt,997,0,13,MANAGER +documents.txt,998,0,17,MANAGER +documents.txt,999,25,37,ENGINEER diff --git a/internal/service/comprehend/test-fixtures/entity_recognizer/documents.txt b/internal/service/comprehend/test-fixtures/entity_recognizer/documents.txt new file mode 100644 index 00000000000..f68319e5bb7 --- /dev/null +++ b/internal/service/comprehend/test-fixtures/entity_recognizer/documents.txt @@ -0,0 +1,1000 @@ +Announcing manager Gerson Parker. +Nickolas Little is a manager. +Alejandra Stiedemann V has been an manager for over a decade. +Eunice Leannon will be the new manager for the team. +Sunny Schmitt is a engineer in the high tech industry. +Anika Gutkowski is a engineer with Example Corp. +Delaney Fisher is retiring as a engineer. +Our latest new employee, Christian Maggio, has been a engineer in the industry for 4 years. +Mathias Hettinger I is retiring as a manager. +Our latest new employee, Elias Quitzon, has been a manager in the industry for 4 years. +Alexandra Wunsch has been an manager for over a decade. +Guido Kemmer joins us as an engineer on the Example project. +Sim Kemmer is a manager with Example Corp. +Help me welcome our newest manager, Vincenza Kertzmann. +Announcing engineer Skye Kuhn Jr.. +Kasandra Cartwright MD is a manager in the high tech industry. +Ettie Schimmel is a manager. +Karlee McCullough Jr. will be the new manager for the team. +Adeline Johnson is a manager with Example Corp. +Cory Morissette has been an manager for over a decade. +Brandy Abshire joins us as an manager on the Example project. +Announcing engineer Jerome Homenick. +Announcing manager Ms. Doris Ziemann. +Help me welcome our newest engineer, Ms. Marlene Larkin. +Amos Kuhlman, an manager, will be presenting the award. +Ana Ortiz II has been a manager for 14 years. +Announcing manager Jewell Konopelski. +Larry Effertz has been a engineer for 14 years. +Ms. Vernice Fay has been an engineer for over a decade. +Miss Dion Ratke is a manager. +Rachelle Lubowitz has been an manager for over a decade. +Rachael Moore is a manager in the high tech industry. +Sabrina Walsh will be the new engineer for the team. +Our latest new employee, Tamara Nicolas, has been a manager in the industry for 4 years. +Our latest new employee, Martin Lynch Sr., has been a manager in the industry for 4 years. +Kaya Wisozk is a manager in the high tech industry. +Our latest new employee, Mrs. Cassandra Robel, has been a engineer in the industry for 4 years. +Donny Schroeder has been an manager for over a decade. +Emmanuel Fay is a manager with Example Corp. +Jefferey Adams will be the new engineer for the team. +Godfrey Feest V, an manager, will be presenting the award. +Melyna Mertz has been a manager for 14 years. +Audreanne Wiza is a manager with Example Corp. +Jarvis O'Conner is a manager. +Mertie Sanford joins us as an manager on the Example project. +Help me welcome our newest engineer, Keshaun Altenwerth. +Aric Beier Sr. is a engineer with Example Corp. +Hoyt Rowe MD is a engineer with Example Corp. +Announcing engineer Aurelia Hintz. +Our latest new employee, Keon Stanton, has been a manager in the industry for 4 years. +Candace Wiegand is a manager with Example Corp. +Flavio Smith is retiring as a manager. +Our latest new employee, Mr. Zachery Toy, has been a manager in the industry for 4 years. +Kaleigh Murazik has been a engineer for 14 years. +Help me welcome our newest engineer, Pattie Kuvalis. +Serena Heidenreich has been a engineer for 14 years. +Our latest new employee, Simone Little, has been a manager in the industry for 4 years. +Ms. Carolina Mante has been a engineer for 14 years. +Julia Lemke has been a manager for 14 years. +Mrs. Meagan Fisher has been an manager for over a decade. +Molly Goldner joins us as an engineer on the Example project. +Announcing manager Mrs. Dax McGlynn. +Tyrique Harber has been an engineer for over a decade. +Mia Larkin II joins us as an manager on the Example project. +Winona Schoen, an manager, will be presenting the award. +Announcing engineer Dr. Antonette Cummings. +Our latest new employee, Mr. Sonya Cassin, has been a manager in the industry for 4 years. +Timothy Bartoletti DDS has been a manager for 14 years. +Our latest new employee, Winifred Reinger, has been a engineer in the industry for 4 years. +Announcing engineer Marcella Bahringer. +Rhea Kohler is a engineer. +Help me welcome our newest engineer, Alia McCullough. +Mr. Israel Gulgowski is a engineer. +Our latest new employee, Jana Wilkinson, has been a engineer in the industry for 4 years. +Marjory Fay will be the new manager for the team. +Alena Mueller is a engineer with Example Corp. +Help me welcome our newest engineer, Kristian Keebler. +Katheryn Dietrich is a manager with Example Corp. +Mya Grady has been an manager for over a decade. +Our latest new employee, Kyra Heidenreich V, has been a engineer in the industry for 4 years. +Announcing manager Dr. Cortez Thiel. +Shyanne Hirthe has been an engineer for over a decade. +Announcing engineer Herta Mohr. +Winfield Thompson is a engineer in the high tech industry. +Help me welcome our newest manager, Miss Bette Dooley. +Mrs. Freida Shanahan has been an engineer for over a decade. +Sunny Towne is a manager in the high tech industry. +Kayley Schneider joins us as an engineer on the Example project. +Announcing manager Anderson Hagenes. +Barrett Paucek Jr. is a manager. +Lillian Koss, an engineer, will be presenting the award. +Announcing engineer Lance Zieme. +Announcing engineer Van Hackett. +Cullen Schamberger is a engineer in the high tech industry. +Arvel Stanton joins us as an manager on the Example project. +Our latest new employee, Nedra Goldner, has been a manager in the industry for 4 years. +Ms. Zetta Lindgren is a manager in the high tech industry. +Help me welcome our newest engineer, Faye Ledner. +Trystan Hilll PhD has been an manager for over a decade. +Arnold Hermann Jr. will be the new engineer for the team. +Hank Towne is a manager in the high tech industry. +Monroe Schmeler has been a manager for 14 years. +Genesis Wintheiser II will be the new engineer for the team. +Angie O'Reilly has been an manager for over a decade. +Deshawn Reinger is a manager in the high tech industry. +Announcing engineer Mrs. Molly Lowe. +Kimberly Osinski is a manager in the high tech industry. +Napoleon Sauer is a engineer in the high tech industry. +Leonardo Champlin is a manager. +Anita Bartell is a manager in the high tech industry. +Mrs. Jennifer Buckridge has been a manager for 14 years. +Patrick Gulgowski is a manager with Example Corp. +Miss Brooks Christiansen, an manager, will be presenting the award. +Help me welcome our newest engineer, Ms. Alejandra Shields. +Callie Lynch will be the new engineer for the team. +Hyman Bruen will be the new engineer for the team. +Ms. Lera Grant, an engineer, will be presenting the award. +Help me welcome our newest manager, Laney West V. +Shyanne Price is a engineer. +Leanna Schoen is a engineer in the high tech industry. +Announcing engineer Clement Bayer. +Mrs. Colt Kozey is retiring as a manager. +Dr. Logan Dickinson will be the new engineer for the team. +Valentin Torp has been a manager for 14 years. +Kathlyn Bechtelar, an manager, will be presenting the award. +Vita Pollich has been a engineer for 14 years. +Benedict Flatley is a manager with Example Corp. +Our latest new employee, Dedrick Corkery V, has been a manager in the industry for 4 years. +Our latest new employee, Shea Kohler, has been a engineer in the industry for 4 years. +Tiana Mertz is a engineer in the high tech industry. +Margarett Kunze has been a engineer for 14 years. +Announcing manager Alan Bashirian. +Dr. Precious Murazik has been an manager for over a decade. +Ms. Karine Langosh has been a engineer for 14 years. +Help me welcome our newest engineer, Letha Skiles. +Help me welcome our newest engineer, Nikko Dooley. +Announcing engineer Filomena McKenzie. +Rosario Grant Sr., an engineer, will be presenting the award. +Gonzalo Douglas V, an engineer, will be presenting the award. +Lempi Pollich will be the new engineer for the team. +Help me welcome our newest engineer, Candida O'Reilly Sr.. +Dena Lind is a engineer with Example Corp. +Blair Renner is a manager with Example Corp. +Imani Roob joins us as an manager on the Example project. +Miss Drake Johns will be the new manager for the team. +Announcing manager Murl Jacobi. +Announcing manager Nicolette Prohaska. +Leif Quigley is a manager with Example Corp. +Hugh Gleichner III has been an manager for over a decade. +Neil Witting is a manager. +Ivah Moore is a engineer in the high tech industry. +Amira Bruen is retiring as a engineer. +Help me welcome our newest engineer, Loy Kerluke. +Our latest new employee, Cleta Berge, has been a manager in the industry for 4 years. +Asa Schaden has been a engineer for 14 years. +Announcing engineer Marlin Nitzsche. +Mellie Hansen has been an engineer for over a decade. +Pauline Willms has been an manager for over a decade. +Giovanna Marquardt is a manager in the high tech industry. +Kristian Conroy IV has been a manager for 14 years. +Announcing engineer Aiyana Hagenes. +Our latest new employee, Melisa Barton Jr., has been a manager in the industry for 4 years. +Help me welcome our newest manager, Robbie Bechtelar. +Citlalli Lind joins us as an engineer on the Example project. +Karlee Lubowitz is a manager in the high tech industry. +Isidro Jerde is a engineer with Example Corp. +Conor Lemke joins us as an manager on the Example project. +Murphy Rutherford joins us as an manager on the Example project. +Omari Schultz has been an manager for over a decade. +Selmer Labadie is a manager in the high tech industry. +Alverta Hilpert, an manager, will be presenting the award. +Our latest new employee, Ali Dooley III, has been a engineer in the industry for 4 years. +Benjamin Lubowitz is a manager. +Trenton Hilll will be the new manager for the team. +Bethel Carroll, an engineer, will be presenting the award. +Nick Lang will be the new manager for the team. +Ms. Chase Graham has been an manager for over a decade. +Announcing engineer Melany Buckridge PhD. +Ursula McGlynn joins us as an engineer on the Example project. +Jackie Kshlerin is a manager. +Jarvis Langosh is a engineer. +Bonnie Bednar will be the new manager for the team. +Announcing engineer Simeon Dickinson. +Annamarie VonRueden MD has been an manager for over a decade. +Ms. Hilton Hagenes has been an engineer for over a decade. +Jaqueline D'Amore has been an manager for over a decade. +Mario Bartell will be the new manager for the team. +Frances Kovacek has been an manager for over a decade. +Help me welcome our newest manager, Avery Lakin. +Brittany Flatley DDS, an engineer, will be presenting the award. +Violette Sauer has been an manager for over a decade. +Dorothy Farrell is a engineer in the high tech industry. +Miss Jordan Crooks is a manager in the high tech industry. +Jadyn West joins us as an manager on the Example project. +Mrs. Johanna Borer is a engineer with Example Corp. +Elyssa Crist joins us as an engineer on the Example project. +Our latest new employee, Carli Kohler, has been a manager in the industry for 4 years. +Dasia Dare has been a engineer for 14 years. +Lane Rath has been an manager for over a decade. +Davion Kunze, an engineer, will be presenting the award. +Vada Stoltenberg, an engineer, will be presenting the award. +London Hagenes has been an engineer for over a decade. +Albin Wintheiser will be the new manager for the team. +Help me welcome our newest engineer, Mr. Eloise Jones. +Rashawn Bechtelar is a manager with Example Corp. +Linwood Casper, an engineer, will be presenting the award. +Our latest new employee, Mr. Phyllis O'Reilly, has been a manager in the industry for 4 years. +Carrie Franecki is a manager in the high tech industry. +Our latest new employee, Mikel Daugherty I, has been a manager in the industry for 4 years. +Announcing manager Jorge Connelly IV. +Victor Cummings is a manager with Example Corp. +Felton Kris has been a manager for 14 years. +Barney Klein is a manager with Example Corp. +Help me welcome our newest manager, Verdie Strosin. +Announcing engineer Izabella Vandervort DDS. +Philip Hodkiewicz has been an manager for over a decade. +Mr. Carol Orn, an manager, will be presenting the award. +Ursula Cormier is a manager. +Ellen Hudson is retiring as a engineer. +Bobby Conn II has been an engineer for over a decade. +Announcing engineer Mathilde Bayer. +Ms. Marcus Ferry has been an engineer for over a decade. +Our latest new employee, Tyshawn Volkman, has been a manager in the industry for 4 years. +Our latest new employee, Ladarius Predovic, has been a engineer in the industry for 4 years. +Our latest new employee, Ally Parisian, has been a manager in the industry for 4 years. +Briana Reinger joins us as an manager on the Example project. +Piper Kutch has been a manager for 14 years. +Armand Ratke is a manager with Example Corp. +Stephon McLaughlin DDS joins us as an engineer on the Example project. +Cordell Cole is a engineer with Example Corp. +Earl Altenwerth is retiring as a engineer. +Our latest new employee, Garrison Lang Jr., has been a manager in the industry for 4 years. +Ahmad Heaney, an engineer, will be presenting the award. +Jed Pollich has been a manager for 14 years. +Help me welcome our newest manager, Hudson Wyman. +Dena Crist DVM has been an engineer for over a decade. +Help me welcome our newest manager, Gino Auer III. +Help me welcome our newest manager, Miss Xavier Farrell. +Announcing engineer Lawrence Considine. +Coby Lesch is a engineer in the high tech industry. +Hardy Mohr joins us as an manager on the Example project. +Dr. Tamara Ryan is retiring as a manager. +Alia Quigley PhD, an engineer, will be presenting the award. +Noelia Bergnaum is a engineer with Example Corp. +Dakota Brown is a engineer. +Elmo Rogahn is a engineer. +Roxanne Weimann joins us as an manager on the Example project. +Gay Langworth is a manager in the high tech industry. +Ellis Ledner joins us as an engineer on the Example project. +Weston Murazik will be the new engineer for the team. +Our latest new employee, Josefa Sauer, has been a manager in the industry for 4 years. +Our latest new employee, Ilene Wyman, has been a manager in the industry for 4 years. +Nia Gottlieb, an manager, will be presenting the award. +Our latest new employee, Crawford Wehner, has been a manager in the industry for 4 years. +Our latest new employee, Brenna Ritchie, has been a manager in the industry for 4 years. +Ms. Mariah Hudson joins us as an manager on the Example project. +Tyra Schneider Sr. has been an manager for over a decade. +Help me welcome our newest manager, Andreane Johns. +Help me welcome our newest engineer, Mrs. Mabel Rice. +Emelia Jaskolski PhD is a engineer. +Spencer Cole II is a engineer in the high tech industry. +Help me welcome our newest manager, Doris Stokes. +Lilian Erdman has been a engineer for 14 years. +Ms. Ramona Torp is retiring as a manager. +Ms. Lauryn Stark, an manager, will be presenting the award. +Israel Greenholt will be the new engineer for the team. +Ms. Boris Leannon is a manager with Example Corp. +Help me welcome our newest manager, Pearlie Swaniawski. +Delores Kilback joins us as an manager on the Example project. +Mariam Schultz is a engineer in the high tech industry. +Dimitri Mueller IV is a manager with Example Corp. +Maud Beahan will be the new manager for the team. +Fletcher Predovic DVM, an engineer, will be presenting the award. +Mrs. Joanne Aufderhar will be the new engineer for the team. +Miss Paul Lowe is retiring as a engineer. +Johnpaul Swift has been an manager for over a decade. +Miss Rowena Pouros is a engineer. +Benjamin Jenkins is a engineer. +Erwin Jenkins will be the new manager for the team. +Ms. Zula Turner, an engineer, will be presenting the award. +Rhiannon Lind is retiring as a manager. +Mrs. Garth Labadie will be the new manager for the team. +Mia King is a manager in the high tech industry. +Ewald Cronin is a engineer with Example Corp. +Carrie Roob III has been an manager for over a decade. +Help me welcome our newest manager, Clementina Schmeler. +Stewart Sipes II has been an engineer for over a decade. +Our latest new employee, Katelin D'Amore, has been a manager in the industry for 4 years. +Announcing manager Verlie Wiegand. +Marie Schaefer is a engineer with Example Corp. +Tillman Boehm is a engineer in the high tech industry. +Announcing manager Jacklyn Kohler. +Katrine Bruen will be the new manager for the team. +Our latest new employee, Lisa Gaylord, has been a engineer in the industry for 4 years. +Virginia Ruecker, an engineer, will be presenting the award. +Mrs. Garnett Christiansen joins us as an engineer on the Example project. +Anderson Weissnat has been an engineer for over a decade. +Help me welcome our newest engineer, Marie Armstrong. +Help me welcome our newest engineer, Prudence Fahey V. +Bria Medhurst will be the new manager for the team. +Announcing engineer Ms. Dewitt Bernhard. +Stanford Miller has been a manager for 14 years. +Freddie Treutel, an manager, will be presenting the award. +Oceane Bayer has been an manager for over a decade. +Ms. Adalberto Lindgren joins us as an manager on the Example project. +Our latest new employee, Meagan Bartoletti, has been a manager in the industry for 4 years. +Wilhelm Kutch, an engineer, will be presenting the award. +Our latest new employee, Khalid Farrell Sr., has been a manager in the industry for 4 years. +Help me welcome our newest engineer, Ms. Allison Zemlak. +Judson Rodriguez MD is a manager with Example Corp. +Help me welcome our newest manager, Mr. Alena Stanton. +Kaylin Kohler has been a engineer for 14 years. +Melany Price is a engineer with Example Corp. +Palma Brekke is a manager. +Help me welcome our newest manager, Ozella Larson. +Earnestine Sanford will be the new engineer for the team. +Kathryne Tromp has been an engineer for over a decade. +Ted Abernathy is a manager with Example Corp. +Our latest new employee, Nelle Waters, has been a engineer in the industry for 4 years. +Help me welcome our newest engineer, Dawn Kautzer. +Ms. Itzel Breitenberg has been an engineer for over a decade. +Meta Gibson is a manager in the high tech industry. +Haven Nitzsche joins us as an engineer on the Example project. +Our latest new employee, Antonetta Kilback I, has been a manager in the industry for 4 years. +Kiara Zboncak joins us as an manager on the Example project. +Our latest new employee, Leola Kris, has been a engineer in the industry for 4 years. +Our latest new employee, Mr. Conrad Hills, has been a manager in the industry for 4 years. +Alize Rogahn has been a engineer for 14 years. +Rudy Hamill is a manager in the high tech industry. +Ms. Celestino Turcotte joins us as an manager on the Example project. +Ms. Annetta Stracke has been an manager for over a decade. +Hailie Hudson is a engineer. +Mrs. Deven Moen joins us as an manager on the Example project. +Callie Larson is a manager with Example Corp. +Quentin Morar joins us as an engineer on the Example project. +Our latest new employee, Antonietta Kuhlman II, has been a manager in the industry for 4 years. +Announcing manager Cristal Shanahan DVM. +Cristopher Boyer joins us as an engineer on the Example project. +Keely Larkin joins us as an engineer on the Example project. +Royce Berge is a engineer with Example Corp. +Announcing engineer Benjamin Hilll. +Rashawn Bogan is retiring as a manager. +Ted Collier has been a manager for 14 years. +Alene Corwin has been an manager for over a decade. +David Hodkiewicz is a manager with Example Corp. +Garland Kuhic has been an manager for over a decade. +Sonya Wilderman is a manager. +Quinn Bradtke Jr. is a manager with Example Corp. +Help me welcome our newest engineer, Ellen Cummerata. +Mason Beatty, an manager, will be presenting the award. +Help me welcome our newest manager, Camylle Muller. +Hadley Upton has been a engineer for 14 years. +Keara Pfeffer is a engineer with Example Corp. +Angie Walsh is retiring as a manager. +Help me welcome our newest manager, Earl Cummings. +Ephraim Marks is retiring as a engineer. +Orval Reichert DDS is a engineer. +Help me welcome our newest engineer, Katheryn Gleichner. +Announcing engineer Jalyn Fay I. +Virginia Keebler DVM is retiring as a engineer. +Raphael Leffler is a engineer. +Juliana Stokes is a manager with Example Corp. +Casper Herman is a manager in the high tech industry. +Announcing manager Vladimir Reilly. +Erin Okuneva has been an manager for over a decade. +Martine White is retiring as a manager. +Tristian Mertz is a manager. +Mr. Sammy Schmitt is a engineer with Example Corp. +Alec Schuster joins us as an manager on the Example project. +Ms. Lorenza Walsh will be the new engineer for the team. +Help me welcome our newest engineer, Eldora Mayert. +Justina Breitenberg will be the new manager for the team. +Our latest new employee, Mariela Grady Jr., has been a engineer in the industry for 4 years. +Kevon Baumbach, an manager, will be presenting the award. +Our latest new employee, Wendell Hayes, has been a engineer in the industry for 4 years. +Pat Aufderhar is a engineer with Example Corp. +Bart Senger joins us as an manager on the Example project. +Kaitlyn Hahn is a engineer. +Our latest new employee, Mrs. Else Kozey, has been a manager in the industry for 4 years. +Mr. Ashton Batz will be the new engineer for the team. +Lilly Koepp has been a engineer for 14 years. +Mrs. Alfredo Cormier has been a manager for 14 years. +Gail Swaniawski DVM is a engineer. +Mrs. Valentina Wilderman has been an engineer for over a decade. +Paxton Doyle is a engineer in the high tech industry. +Jarret Block PhD joins us as an manager on the Example project. +Arnaldo Blanda joins us as an manager on the Example project. +Aiden Orn has been an manager for over a decade. +Florine West is a manager. +Help me welcome our newest manager, Sincere Harber. +Announcing engineer Joan Ziemann. +Katelyn Schultz has been an engineer for over a decade. +Maximus Gleichner is a manager in the high tech industry. +Announcing manager Elenor Schuster. +Marcelino Kautzer will be the new engineer for the team. +Lea Schulist Sr. has been a engineer for 14 years. +Jeanne Carter MD is a manager in the high tech industry. +Kayleigh Goldner DDS is a engineer in the high tech industry. +Hilario Denesik I is a manager with Example Corp. +Shirley Reichert has been a manager for 14 years. +Kris Dickens is a engineer. +Gene Frami, an manager, will be presenting the award. +Sadye Jacobson is a manager in the high tech industry. +Buck Cremin joins us as an engineer on the Example project. +Our latest new employee, Coty Lesch, has been a engineer in the industry for 4 years. +Dr. Kim Mertz has been an engineer for over a decade. +Randy Sanford will be the new manager for the team. +Help me welcome our newest manager, Levi Kirlin. +Announcing engineer Davin Yundt. +Help me welcome our newest engineer, Enola Bins. +Trent Kuvalis, an engineer, will be presenting the award. +Announcing engineer Jake Powlowski. +Ms. Ashlee Emmerich, an manager, will be presenting the award. +Hannah Davis, an engineer, will be presenting the award. +Wayne Champlin joins us as an engineer on the Example project. +Nikki Conn Jr. is a manager. +Announcing engineer Carli Bauch. +Norbert Feest is a manager in the high tech industry. +Robbie Wintheiser has been an engineer for over a decade. +Leta Abshire is a engineer in the high tech industry. +Fannie Walker is a engineer. +Heber Wilkinson is a manager with Example Corp. +Announcing manager Willie Bernier III. +Help me welcome our newest engineer, Orlando Price. +Brandt Schowalter is a manager. +Mohammed Stokes is retiring as a engineer. +Isai Mraz is a engineer in the high tech industry. +Kadin Lemke will be the new manager for the team. +Maribel Jerde has been an manager for over a decade. +Myrna Kessler is a manager. +Meredith Tremblay is retiring as a engineer. +Announcing engineer Mr. Jerad Schneider. +Announcing manager Lenny Pfeffer. +Carolyne Klocko DVM will be the new manager for the team. +Our latest new employee, Monica Schulist, has been a engineer in the industry for 4 years. +Anika Larson V is a manager. +Domenick Pacocha is retiring as a engineer. +Miss Harmon Pfannerstill has been a engineer for 14 years. +Announcing manager Mr. Annabell Pouros. +Dr. Brisa Stroman has been an manager for over a decade. +Help me welcome our newest manager, Jade Stoltenberg. +Miss Mario Wolff joins us as an engineer on the Example project. +Ms. Savannah Gaylord is retiring as a manager. +Dejah Jones, an manager, will be presenting the award. +Hector Kulas, an manager, will be presenting the award. +Graciela Goodwin will be the new manager for the team. +Jocelyn Sauer is a manager. +Miss Lew Hansen will be the new manager for the team. +Fannie Fay DDS is a engineer with Example Corp. +Dr. Jordan Klocko is a engineer with Example Corp. +Kathlyn Lynch is a manager in the high tech industry. +Leann Botsford has been an engineer for over a decade. +Ervin Larson has been a manager for 14 years. +Allie Von is a manager in the high tech industry. +Johanna Kohler III has been a manager for 14 years. +Our latest new employee, Hilbert Armstrong, has been a engineer in the industry for 4 years. +Tanner Balistreri IV has been an manager for over a decade. +Abagail Shields has been an engineer for over a decade. +Help me welcome our newest engineer, Gia Cremin. +Mrs. Buford Oberbrunner is retiring as a engineer. +Madelyn White is retiring as a manager. +Announcing manager Abdullah Effertz. +Reva Stark will be the new engineer for the team. +Camryn McKenzie will be the new manager for the team. +Juwan Pouros will be the new manager for the team. +Gene Cassin is a manager in the high tech industry. +Our latest new employee, Felicia Kunde, has been a engineer in the industry for 4 years. +Our latest new employee, Jeremie Anderson, has been a manager in the industry for 4 years. +Our latest new employee, Katheryn Hickle Jr., has been a manager in the industry for 4 years. +Our latest new employee, Edwina Hamill IV, has been a manager in the industry for 4 years. +Adriana Cassin DVM has been a manager for 14 years. +Nelda Rowe joins us as an engineer on the Example project. +Rodrigo Kulas V joins us as an engineer on the Example project. +Jaiden Williamson is a manager in the high tech industry. +Announcing manager Cristopher Williamson. +Mr. Jay Krajcik, an engineer, will be presenting the award. +Announcing manager Francesco Miller. +Brenna Reinger, an manager, will be presenting the award. +Mr. Mollie Stanton has been an manager for over a decade. +Coby Schowalter has been a engineer for 14 years. +Our latest new employee, Estefania Armstrong II, has been a manager in the industry for 4 years. +Announcing engineer Aimee Nienow. +Kimberly Batz will be the new engineer for the team. +Miss Sienna Pfannerstill is retiring as a engineer. +Johnathon Hammes is retiring as a engineer. +Julien Hansen is a manager in the high tech industry. +Mrs. Emerson Waelchi will be the new manager for the team. +Malcolm Streich is a manager with Example Corp. +Aurelio Lebsack is retiring as a engineer. +Juana Grady has been a engineer for 14 years. +Kiel Lakin is a manager in the high tech industry. +Our latest new employee, Sarai Keeling, has been a engineer in the industry for 4 years. +Emilia Crona has been a engineer for 14 years. +Georgianna Kris is a manager in the high tech industry. +Maida Heller is retiring as a manager. +Jena Feeney is a engineer with Example Corp. +Mabelle Keeling has been an manager for over a decade. +Chris Bergstrom has been an engineer for over a decade. +Our latest new employee, Audrey Block DDS, has been a engineer in the industry for 4 years. +Our latest new employee, Louvenia Kuhn, has been a engineer in the industry for 4 years. +Thomas O'Keefe has been a manager for 14 years. +Our latest new employee, Darby Klocko, has been a manager in the industry for 4 years. +Arlene Weimann, an manager, will be presenting the award. +Our latest new employee, Corbin Jones MD, has been a engineer in the industry for 4 years. +Lamar Mraz joins us as an engineer on the Example project. +Miss Onie Krajcik is a manager with Example Corp. +Kamille Schaefer, an manager, will be presenting the award. +Jack Borer, an engineer, will be presenting the award. +Reese Heaney has been a manager for 14 years. +Ilene Kovacek will be the new engineer for the team. +Trace Bailey will be the new engineer for the team. +Our latest new employee, Wava Donnelly, has been a engineer in the industry for 4 years. +Mona Lakin has been a manager for 14 years. +Weldon Heaney joins us as an manager on the Example project. +Norris Labadie has been a engineer for 14 years. +Bridgette Brown has been an manager for over a decade. +Osborne Kertzmann is a manager with Example Corp. +Announcing engineer Verlie Bruen. +Enrique Ullrich is a engineer with Example Corp. +Dr. Asia Purdy joins us as an engineer on the Example project. +Announcing manager Lindsey Predovic DDS. +Maxine Mosciski is retiring as a manager. +Sydni Stoltenberg is retiring as a engineer. +Paige Buckridge will be the new engineer for the team. +Miss Laverne Dach has been an manager for over a decade. +Murl Abshire is a manager in the high tech industry. +Lou Friesen is retiring as a manager. +Announcing engineer Keenan Fahey. +Ashleigh Schultz, an engineer, will be presenting the award. +Mrs. Keshaun Lesch has been an engineer for over a decade. +Announcing engineer Jeffrey Langosh. +Mckenzie Boyle, an engineer, will be presenting the award. +Hipolito Price PhD joins us as an manager on the Example project. +Lesley Adams III joins us as an engineer on the Example project. +Mya Howe is a engineer with Example Corp. +Nick Kutch Sr. has been a manager for 14 years. +Our latest new employee, Ms. Winfield Wilkinson, has been a engineer in the industry for 4 years. +Leopold Schulist is a engineer with Example Corp. +Announcing engineer Orval Prosacco. +Wilmer Mueller has been an manager for over a decade. +Karina Batz has been a manager for 14 years. +Our latest new employee, Luigi Abbott, has been a manager in the industry for 4 years. +Pamela Miller is a manager in the high tech industry. +Emelie Marquardt is a engineer with Example Corp. +Zola Beier is a manager in the high tech industry. +Mr. Elva Ritchie joins us as an engineer on the Example project. +Mrs. Otis Quitzon is a manager in the high tech industry. +Our latest new employee, Dr. Willow Jacobs, has been a manager in the industry for 4 years. +Cathryn Koss joins us as an manager on the Example project. +Ms. Alivia Ernser is retiring as a manager. +Timothy Mohr is a engineer. +Mrs. Jaylan Wuckert is retiring as a manager. +Emerald Waelchi is a engineer. +Vernon Heathcote is retiring as a manager. +Announcing engineer Lavinia Ruecker. +Mr. Quinn Altenwerth is retiring as a manager. +Alejandra Marks, an manager, will be presenting the award. +Mr. Leo Wuckert has been an manager for over a decade. +Jayce Schiller MD is a manager in the high tech industry. +Elenora Ebert Jr. will be the new engineer for the team. +Announcing manager Dr. Rose Wyman. +Help me welcome our newest manager, Wade Orn. +Iva Marks Sr., an manager, will be presenting the award. +Margaret Pouros will be the new manager for the team. +Barton Deckow has been an manager for over a decade. +Miss Lesly Balistreri will be the new engineer for the team. +Mr. Jacquelyn Reynolds joins us as an engineer on the Example project. +Announcing manager Doyle Heidenreich. +Announcing engineer Heidi Ruecker. +Mr. Alvis Moen joins us as an manager on the Example project. +Dr. Garnet Brown is a engineer. +Yolanda Beier is a engineer with Example Corp. +Soledad Macejkovic joins us as an engineer on the Example project. +Urban Lowe has been a engineer for 14 years. +Devyn Schmidt has been an manager for over a decade. +Barbara Flatley is a manager in the high tech industry. +Patsy Sanford PhD has been an engineer for over a decade. +Mrs. Rubye Blanda is a engineer. +Caleigh Klocko is a engineer. +Kali Dietrich has been an manager for over a decade. +Ms. Weldon Hudson is retiring as a engineer. +Help me welcome our newest engineer, Vallie Huel. +Sven O'Keefe III joins us as an engineer on the Example project. +Help me welcome our newest engineer, Gerardo Wehner Sr.. +Kyle Kirlin is a manager in the high tech industry. +Help me welcome our newest engineer, Marianne Berge Jr.. +Ms. Cristal Connelly is retiring as a manager. +Kailey Spinka has been an manager for over a decade. +Jeremie Morar has been an manager for over a decade. +Our latest new employee, Daija Lind, has been a engineer in the industry for 4 years. +Arvel McDermott is a engineer. +Dr. Nicholas Gorczany has been a manager for 14 years. +Anne Leuschke has been a manager for 14 years. +Gerda Cronin has been a engineer for 14 years. +Ms. Coty Rolfson is retiring as a engineer. +Announcing engineer Kareem Gerhold. +Announcing engineer Mrs. Nico Mann. +Corbin Bartell is a engineer in the high tech industry. +Theresa Gulgowski will be the new manager for the team. +Carmelo Boyer is retiring as a manager. +Elinore Schulist III joins us as an manager on the Example project. +Katarina Schultz joins us as an manager on the Example project. +Deven Rodriguez II is a manager in the high tech industry. +Miss Bruce Friesen is a manager in the high tech industry. +Marcelle Schowalter joins us as an manager on the Example project. +Albertha Murphy PhD has been an manager for over a decade. +Elmore Doyle is a engineer. +Our latest new employee, Reymundo Jaskolski, has been a engineer in the industry for 4 years. +Stephania Swaniawski I joins us as an manager on the Example project. +Stewart Veum has been an manager for over a decade. +Help me welcome our newest manager, Nathanael Bartell. +Retha Rempel is a engineer. +Isidro Aufderhar joins us as an manager on the Example project. +Florencio Mohr, an manager, will be presenting the award. +Zella Weimann is a engineer with Example Corp. +Khalid Macejkovic will be the new engineer for the team. +Our latest new employee, Geraldine Torp, has been a engineer in the industry for 4 years. +Presley Marks will be the new engineer for the team. +Mrs. Eve Bartoletti is retiring as a engineer. +Corine Schimmel, an manager, will be presenting the award. +Citlalli Goldner DDS, an manager, will be presenting the award. +Zakary Botsford, an manager, will be presenting the award. +Florida Reilly is retiring as a engineer. +Mr. Patsy Doyle joins us as an manager on the Example project. +Help me welcome our newest engineer, Emily Hayes II. +Dr. Johann Turcotte will be the new engineer for the team. +Dr. Darion Dietrich is a engineer in the high tech industry. +Norris Brekke is a manager in the high tech industry. +Janessa Marquardt joins us as an manager on the Example project. +Felicita Wintheiser MD has been an manager for over a decade. +Melyssa Muller, an engineer, will be presenting the award. +Vivienne Weissnat DDS has been a engineer for 14 years. +Ford Gerlach is a engineer. +Keenan Kertzmann is a engineer in the high tech industry. +Tobin Goyette joins us as an engineer on the Example project. +Help me welcome our newest manager, Cecilia Green. +Abe Fisher has been an manager for over a decade. +Mrs. Annabell Morissette is a manager. +Announcing manager Danny Kautzer III. +Gerard Cruickshank joins us as an engineer on the Example project. +Joy Okuneva DDS, an manager, will be presenting the award. +Ezequiel Macejkovic joins us as an engineer on the Example project. +Vernie Bradtke IV, an engineer, will be presenting the award. +Trycia Muller is a engineer. +Clotilde Ankunding is a engineer in the high tech industry. +Mr. Chaya Abshire, an engineer, will be presenting the award. +Announcing manager Hanna Roob. +Ronny Dietrich will be the new engineer for the team. +Derek Durgan DVM will be the new manager for the team. +Demetrius West will be the new manager for the team. +Macey Nikolaus is retiring as a manager. +Edison Gottlieb III is a manager in the high tech industry. +Bo Collins is a engineer with Example Corp. +Michaela Pagac PhD has been a manager for 14 years. +Mireille Kunde I is a engineer with Example Corp. +Duncan Kulas will be the new manager for the team. +Mrs. Xzavier Smitham is a engineer with Example Corp. +Announcing manager Mr. Adrianna Baumbach. +Shad Rolfson is a manager with Example Corp. +Mr. Dimitri Baumbach, an manager, will be presenting the award. +Our latest new employee, Samara Schultz, has been a manager in the industry for 4 years. +Mrs. Brant Kautzer is a manager in the high tech industry. +Tierra Greenholt is a engineer. +Our latest new employee, Otho Kub, has been a manager in the industry for 4 years. +Ana Harber will be the new manager for the team. +Our latest new employee, Ted Mertz Sr., has been a engineer in the industry for 4 years. +Uriel Zieme will be the new manager for the team. +Mr. Adaline Wolff has been an engineer for over a decade. +Help me welcome our newest manager, Mrs. Maurice Senger. +Ada Gleason has been an manager for over a decade. +Edwina Bernier DVM has been an engineer for over a decade. +Elva Homenick is retiring as a engineer. +Our latest new employee, Mrs. Shane Powlowski, has been a manager in the industry for 4 years. +Obie Nikolaus has been a manager for 14 years. +Ottis Jakubowski is a manager. +Mr. Armand Leannon is a engineer in the high tech industry. +Jaime Kuvalis joins us as an engineer on the Example project. +Help me welcome our newest engineer, Loyce VonRueden Jr.. +Evangeline Johns joins us as an manager on the Example project. +Federico Halvorson is a manager in the high tech industry. +Sylvester Gerlach is a manager in the high tech industry. +Our latest new employee, Ashly Wunsch V, has been a manager in the industry for 4 years. +Rowland Miller joins us as an manager on the Example project. +Bryon Kunde has been a manager for 14 years. +Denis Ernser has been an engineer for over a decade. +Jovanny O'Reilly DVM is a engineer with Example Corp. +Lazaro Hermiston is retiring as a manager. +Kelly Stehr is a engineer. +Oda Fadel is a engineer with Example Corp. +Percival Armstrong is a engineer. +Caleigh Schimmel joins us as an manager on the Example project. +Tyrique Pfeffer has been a engineer for 14 years. +Adell Leuschke is retiring as a engineer. +Dr. Cade Farrell will be the new engineer for the team. +Gisselle Doyle is retiring as a manager. +Lily Reinger will be the new manager for the team. +Jeffrey Gleason has been a engineer for 14 years. +Tad Huel, an engineer, will be presenting the award. +Connor Conn joins us as an manager on the Example project. +Mr. Cathrine Casper is a engineer with Example Corp. +Our latest new employee, Dr. Beryl Rempel, has been a manager in the industry for 4 years. +Carlie Steuber joins us as an manager on the Example project. +Rose Frami IV is a engineer. +Mr. Tyrel Pagac joins us as an manager on the Example project. +Our latest new employee, Morton Trantow, has been a engineer in the industry for 4 years. +Lola Ortiz has been an manager for over a decade. +Kelton Champlin has been a manager for 14 years. +Our latest new employee, Owen Mayert, has been a engineer in the industry for 4 years. +Johnny Witting joins us as an manager on the Example project. +Thea Rolfson will be the new manager for the team. +Reanna Schmidt has been an engineer for over a decade. +Help me welcome our newest manager, Ian Stehr. +Mr. Patsy Purdy will be the new manager for the team. +Brady Ritchie will be the new engineer for the team. +Our latest new employee, Thea Effertz, has been a manager in the industry for 4 years. +Gerry Veum has been a engineer for 14 years. +Corene Adams is retiring as a manager. +Julian Kutch has been a manager for 14 years. +Mrs. Joe Connelly is a engineer. +Announcing manager Adolphus Paucek. +Jasmin Ledner II is a engineer with Example Corp. +Dr. Osbaldo Beatty will be the new engineer for the team. +Dr. Mckenna Haag is a manager with Example Corp. +Help me welcome our newest engineer, Abdiel Connelly DVM. +Help me welcome our newest manager, Liliana Baumbach III. +Willard Kuvalis V is retiring as a engineer. +Carolyn Jaskolski Jr., an manager, will be presenting the award. +Reta Franecki is retiring as a engineer. +Percival O'Kon has been an engineer for over a decade. +Kamryn Rath is a manager with Example Corp. +Hailey Dooley is a manager in the high tech industry. +Mrs. Brycen West has been an engineer for over a decade. +Margarette Miller will be the new manager for the team. +Our latest new employee, Cristian Pagac, has been a manager in the industry for 4 years. +Rosalee Bechtelar, an manager, will be presenting the award. +Help me welcome our newest manager, Lessie Lesch. +Iva Hegmann joins us as an manager on the Example project. +Hallie Schroeder is a manager. +Mr. Lola Volkman is a engineer in the high tech industry. +Arianna Wolf DDS has been an manager for over a decade. +Elliot Trantow has been a manager for 14 years. +Darrion Rath PhD has been a engineer for 14 years. +Coralie Effertz V has been an engineer for over a decade. +Our latest new employee, Ms. Corrine Effertz, has been a engineer in the industry for 4 years. +Our latest new employee, Ellie Keebler, has been a engineer in the industry for 4 years. +Tyrese Pfeffer is a engineer in the high tech industry. +Announcing manager Jayce Roberts. +Isobel Veum is retiring as a engineer. +Raphaelle Breitenberg is retiring as a engineer. +Maudie Labadie I has been an engineer for over a decade. +Rosario Langosh MD has been a engineer for 14 years. +Raheem Mohr joins us as an manager on the Example project. +Avery Lind joins us as an engineer on the Example project. +Nichole Waters has been a engineer for 14 years. +Blaise Gislason I has been a manager for 14 years. +Everette D'Amore has been a engineer for 14 years. +Darwin Conroy is a manager in the high tech industry. +Abdullah Heathcote is retiring as a engineer. +Burnice Treutel has been an manager for over a decade. +Libbie O'Hara is a engineer with Example Corp. +Rowan Will has been an manager for over a decade. +Gudrun Gleason is retiring as a engineer. +Our latest new employee, Fannie Quitzon, has been a manager in the industry for 4 years. +Help me welcome our newest engineer, Terence Gutkowski. +Tyshawn Rowe is a manager. +Jaylan Sanford, an manager, will be presenting the award. +Camille Schaden DVM, an manager, will be presenting the award. +Ms. Blaze Emmerich will be the new manager for the team. +Announcing engineer Sonny Stoltenberg. +Elsie Jacobson is a manager. +Our latest new employee, London Jacobs, has been a manager in the industry for 4 years. +Mr. Hassie Kuhn is retiring as a engineer. +Raul Bogan MD is a engineer. +Adrian Abshire joins us as an manager on the Example project. +Our latest new employee, Golden Kreiger, has been a manager in the industry for 4 years. +Deven Stiedemann I, an manager, will be presenting the award. +Hilario Koepp PhD has been a manager for 14 years. +Maynard Herzog will be the new manager for the team. +Announcing manager Nathaniel Torp. +Courtney Strosin is a manager with Example Corp. +Emely Lowe is a engineer with Example Corp. +Vilma Weber is retiring as a engineer. +Announcing engineer Ms. Carlee Littel. +Help me welcome our newest engineer, Hayden Mills. +Ervin Schimmel is a engineer. +Gino Ortiz is a engineer in the high tech industry. +Help me welcome our newest manager, Amani Conroy. +Announcing manager Korbin Lowe. +Turner Bogan I will be the new engineer for the team. +Ms. Jabari Bauch has been an manager for over a decade. +Mrs. Breanne Morissette is a engineer in the high tech industry. +Our latest new employee, Crystel Doyle, has been a manager in the industry for 4 years. +Help me welcome our newest engineer, Isabel VonRueden. +Dayne Cremin is a engineer. +Help me welcome our newest manager, Waino Armstrong. +Deborah Armstrong is retiring as a manager. +Ashlynn Mante DVM is a engineer in the high tech industry. +Karlie Pollich Jr. joins us as an engineer on the Example project. +Maeve Schroeder is a manager in the high tech industry. +Hanna Fadel, an engineer, will be presenting the award. +Delphia O'Hara has been a manager for 14 years. +Jamir Hammes has been an engineer for over a decade. +Nigel Ortiz is retiring as a engineer. +Pauline Ritchie is a manager. +Nicholaus Toy has been an engineer for over a decade. +Freddy Okuneva joins us as an manager on the Example project. +Announcing engineer Brionna Fritsch. +Our latest new employee, Maiya Mills, has been a engineer in the industry for 4 years. +Alia Hoeger PhD has been a manager for 14 years. +Alvina Mertz is a engineer in the high tech industry. +Help me welcome our newest engineer, Raymundo Hintz. +Zack Stamm is a engineer in the high tech industry. +Dayne Klocko has been a manager for 14 years. +Announcing engineer Kyla Cremin. +Izabella Bernhard will be the new engineer for the team. +Zena Yundt is a engineer in the high tech industry. +Announcing manager Daron Schuppe. +Mr. Amira Marvin joins us as an manager on the Example project. +Boris Morar will be the new manager for the team. +Esperanza Batz is retiring as a engineer. +Dortha Macejkovic I has been an manager for over a decade. +Porter Dach V, an engineer, will be presenting the award. +Kailyn Flatley I is a manager with Example Corp. +Celine O'Keefe has been a manager for 14 years. +Obie Rodriguez, an manager, will be presenting the award. +Cade Gorczany joins us as an engineer on the Example project. +Myles Shanahan is a engineer. +Jayne Wiza will be the new engineer for the team. +Julius Huel has been an manager for over a decade. +Ms. Rowena Kihn, an engineer, will be presenting the award. +Ena Wehner is a manager with Example Corp. +Clovis Cartwright will be the new manager for the team. +Mr. Marcelo D'Amore is a manager. +Meggie Prosacco has been an engineer for over a decade. +Lisa Schamberger PhD has been an engineer for over a decade. +Mrs. Lyda Bayer, an manager, will be presenting the award. +Newell Hettinger joins us as an manager on the Example project. +Melany Wolf, an manager, will be presenting the award. +Emil Schaefer has been an manager for over a decade. +Samson Trantow has been a manager for 14 years. +Maida Marquardt is a engineer. +Johnpaul Howe MD is a manager with Example Corp. +Our latest new employee, Mrs. Adah Lubowitz, has been a engineer in the industry for 4 years. +Ms. Imelda Kohler, an manager, will be presenting the award. +Manuela Frami I, an engineer, will be presenting the award. +Noelia Padberg has been an manager for over a decade. +Una Eichmann DDS is a engineer. +Elta Nolan has been an engineer for over a decade. +Jaron Wyman is a engineer in the high tech industry. +Help me welcome our newest manager, Kayla Windler Sr.. +Mrs. Zetta Stiedemann joins us as an manager on the Example project. +Dr. Abner Adams is retiring as a manager. +Brenden Ortiz is retiring as a manager. +German Funk is a engineer. +Mr. Liliane Konopelski, an manager, will be presenting the award. +Jarrett Morar is a manager in the high tech industry. +Parker Huels is a manager in the high tech industry. +Mrs. Alvah Bayer is a engineer with Example Corp. +Wilhelm Parker Jr. is a engineer in the high tech industry. +Leo Mertz will be the new engineer for the team. +Corine Hills is a engineer. +Coy Raynor Sr. is a engineer. +Help me welcome our newest engineer, Mallie Streich DVM. +Daisy Hoeger is a manager in the high tech industry. +Michelle Hickle is a engineer with Example Corp. +Nolan Douglas will be the new engineer for the team. +Vivian Bernier is retiring as a engineer. +Announcing engineer Brigitte Toy. +Help me welcome our newest engineer, Aniyah Schoen. +Emmie Bins is a engineer. +Mazie Weimann, an manager, will be presenting the award. +Carole Aufderhar will be the new engineer for the team. +Bernhard O'Kon will be the new engineer for the team. +Flavio Moore Sr. is a manager with Example Corp. +Our latest new employee, Justina Wuckert, has been a engineer in the industry for 4 years. +Meredith Jones joins us as an engineer on the Example project. +Help me welcome our newest manager, Gene Champlin. +Clare Fay, an manager, will be presenting the award. +Lesly Johnston II is retiring as a manager. +Our latest new employee, Cristian Kling, has been a manager in the industry for 4 years. +Candido Littel is a manager. +Help me welcome our newest engineer, Mrs. Gregory Ritchie. +Lucio Sawayn is a manager with Example Corp. +Announcing manager Derick Rath DVM. +Gabriella Dietrich is a engineer in the high tech industry. +Lula Spencer DVM has been an engineer for over a decade. +Help me welcome our newest engineer, Horacio Kulas. +Davin Vandervort DDS has been a engineer for 14 years. +Ms. Avery Wisoky will be the new engineer for the team. +Talon Williamson MD, an manager, will be presenting the award. +Gerald Hahn has been a manager for 14 years. +Ettie Yost is retiring as a manager. +Abdullah Mosciski is retiring as a engineer. +Mrs. Marielle Bosco is a engineer in the high tech industry. +Kory Batz joins us as an manager on the Example project. +Noelia Kovacek, an engineer, will be presenting the award. +Kyleigh Nienow is a manager with Example Corp. +Alize Lind will be the new engineer for the team. +Ellsworth Altenwerth has been an engineer for over a decade. +Domenic Mayer has been a engineer for 14 years. +Ms. Geovanny Satterfield has been an engineer for over a decade. +Ella Daniel is a manager with Example Corp. +Kylee Bogisich PhD has been an engineer for over a decade. +Ryder Wilkinson Sr. is a manager in the high tech industry. +Help me welcome our newest engineer, Marina Schaefer. +Ms. Paige Bartell is a manager in the high tech industry. +Mitchel Murray has been an engineer for over a decade. +Tyler Quigley, an manager, will be presenting the award. +Veronica Kreiger has been a engineer for 14 years. +Halie Goldner has been an engineer for over a decade. +Ryder Lakin has been an engineer for over a decade. +Chloe Legros is a engineer. +Dariana O'Conner joins us as an engineer on the Example project. +Era Bins Jr. is a engineer with Example Corp. +Help me welcome our newest manager, Laila Reichert. +Dedrick Kuhic V has been a engineer for 14 years. +Haylee Price Jr. is retiring as a engineer. +Help me welcome our newest manager, Callie Shields. +Jarrod Fahey will be the new manager for the team. +Earlene Cremin is a engineer in the high tech industry. +Ellie Bergstrom will be the new manager for the team. +Armando Grady has been a engineer for 14 years. +Announcing engineer Dr. Lamar Hessel. +Joe Runolfsson Sr. is a engineer with Example Corp. +Announcing manager Manley Oberbrunner. +Meta Weissnat II has been an engineer for over a decade. +Dagmar Batz IV is a engineer with Example Corp. +Our latest new employee, Susie Bayer, has been a engineer in the industry for 4 years. +Help me welcome our newest engineer, Randi Howell. +Joanne Rau is a manager in the high tech industry. +Buck Stark is a engineer. +Shane Donnelly is a engineer with Example Corp. +Quincy Casper V is retiring as a engineer. +Lafayette Grimes will be the new manager for the team. +Mrs. Jody Beer will be the new engineer for the team. +Miss Corene Schamberger has been an engineer for over a decade. +Dr. Jesse Baumbach is retiring as a engineer. +Brenna Quigley Jr. is a manager. +Ms. Viviane Bins joins us as an engineer on the Example project. +Help me welcome our newest manager, Edgar Johnson. +Mr. Tracy Beier has been a engineer for 14 years. +Juvenal Ortiz has been a engineer for 14 years. +Dr. Nat Pagac is retiring as a manager. +Our latest new employee, Julio Mitchell, has been a engineer in the industry for 4 years. +Help me welcome our newest engineer, Clarissa Mraz Jr.. +Dustin Grady will be the new manager for the team. +Brennon Bayer is a engineer. +Mrs. Birdie Nienow has been a manager for 14 years. +Announcing engineer Randal Sauer Sr.. +Verda Kozey will be the new engineer for the team. +Chesley Hickle is a engineer with Example Corp. +Miss Rico Block has been a engineer for 14 years. +Gaetano Lindgren has been a manager for 14 years. +Hope Hauck will be the new engineer for the team. +Percival O'Connell is a engineer in the high tech industry. +Melyna Leuschke is a manager. +Our latest new employee, Adan Collins, has been a manager in the industry for 4 years. +Daryl Bashirian has been an engineer for over a decade. +Kara Welch, an manager, will be presenting the award. +Norberto Swift has been an engineer for over a decade. +Effie Champlin Jr. will be the new engineer for the team. +Dr. Julia Metz joins us as an manager on the Example project. +Janice Witting is a manager in the high tech industry. +Bruce Eichmann, an manager, will be presenting the award. +Isobel Swift is a engineer. +Earnestine Mayer MD has been an manager for over a decade. +Michele Bashirian is a engineer in the high tech industry. +Janick Crona is a engineer in the high tech industry. +Hank Fisher III has been a manager for 14 years. +Miss Aliya Skiles is a engineer. +Herbert Orn has been an manager for over a decade. +Our latest new employee, Aglae Baumbach, has been a engineer in the industry for 4 years. +Gayle Carter will be the new engineer for the team. +Announcing manager Creola Kautzer. +Announcing manager Theresa Hauck. +Ms. Patience Wintheiser, an manager, will be presenting the award. +Announcing engineer Sebastian Rutherford DDS. +Ara Pollich I has been a engineer for 14 years. +Carlos Baumbach has been an manager for over a decade. +Hulda Schroeder DVM is a engineer with Example Corp. +Stanton Torp joins us as an manager on the Example project. +Our latest new employee, Ceasar Franecki, has been a manager in the industry for 4 years. +Lelah Miller is a engineer. +Wyman Schultz is a manager in the high tech industry. +Mae Harris V will be the new manager for the team. +Help me welcome our newest engineer, Hortense Koelpin. +Our latest new employee, Wilmer Deckow, has been a engineer in the industry for 4 years. +Zaria Ferry has been an engineer for over a decade. +Help me welcome our newest engineer, Pierre Cronin. +Ms. Brenna Leffler is a engineer with Example Corp. +Announcing engineer Dr. Keara Price. +Announcing manager Jane Schroeder. +Reymundo Heathcote has been a manager for 14 years. +Elton Schiller II is a manager with Example Corp. +Irma Blanda is a manager with Example Corp. +Mireya Turner, an manager, will be presenting the award. +Dawson Streich will be the new manager for the team. +Gianni Cassin is a manager in the high tech industry. +Johnathan Kuhic V joins us as an manager on the Example project. +Our latest new employee, Lacey Sawayn, has been a engineer in the industry for 4 years. diff --git a/internal/service/comprehend/test-fixtures/entity_recognizer/entitylist.csv b/internal/service/comprehend/test-fixtures/entity_recognizer/entitylist.csv new file mode 100644 index 00000000000..f1080f9213f --- /dev/null +++ b/internal/service/comprehend/test-fixtures/entity_recognizer/entitylist.csv @@ -0,0 +1,1001 @@ +Text,Type +Gerson Parker,MANAGER +Nickolas Little,MANAGER +Alejandra Stiedemann V,MANAGER +Eunice Leannon,MANAGER +Sunny Schmitt,ENGINEER +Anika Gutkowski,ENGINEER +Delaney Fisher,ENGINEER +Christian Maggio,ENGINEER +Mathias Hettinger I,MANAGER +Elias Quitzon,MANAGER +Alexandra Wunsch,MANAGER +Guido Kemmer,ENGINEER +Sim Kemmer,MANAGER +Vincenza Kertzmann,MANAGER +Skye Kuhn Jr.,ENGINEER +Kasandra Cartwright MD,MANAGER +Ettie Schimmel,MANAGER +Karlee McCullough Jr.,MANAGER +Adeline Johnson,MANAGER +Cory Morissette,MANAGER +Brandy Abshire,MANAGER +Jerome Homenick,ENGINEER +Ms. Doris Ziemann,MANAGER +Ms. Marlene Larkin,ENGINEER +Amos Kuhlman,MANAGER +Ana Ortiz II,MANAGER +Jewell Konopelski,MANAGER +Larry Effertz,ENGINEER +Ms. Vernice Fay,ENGINEER +Miss Dion Ratke,MANAGER +Rachelle Lubowitz,MANAGER +Rachael Moore,MANAGER +Sabrina Walsh,ENGINEER +Tamara Nicolas,MANAGER +Martin Lynch Sr.,MANAGER +Kaya Wisozk,MANAGER +Mrs. Cassandra Robel,ENGINEER +Donny Schroeder,MANAGER +Emmanuel Fay,MANAGER +Jefferey Adams,ENGINEER +Godfrey Feest V,MANAGER +Melyna Mertz,MANAGER +Audreanne Wiza,MANAGER +Jarvis O'Conner,MANAGER +Mertie Sanford,MANAGER +Keshaun Altenwerth,ENGINEER +Aric Beier Sr.,ENGINEER +Hoyt Rowe MD,ENGINEER +Aurelia Hintz,ENGINEER +Keon Stanton,MANAGER +Candace Wiegand,MANAGER +Flavio Smith,MANAGER +Mr. Zachery Toy,MANAGER +Kaleigh Murazik,ENGINEER +Pattie Kuvalis,ENGINEER +Serena Heidenreich,ENGINEER +Simone Little,MANAGER +Ms. Carolina Mante,ENGINEER +Julia Lemke,MANAGER +Mrs. Meagan Fisher,MANAGER +Molly Goldner,ENGINEER +Mrs. Dax McGlynn,MANAGER +Tyrique Harber,ENGINEER +Mia Larkin II,MANAGER +Winona Schoen,MANAGER +Dr. Antonette Cummings,ENGINEER +Mr. Sonya Cassin,MANAGER +Timothy Bartoletti DDS,MANAGER +Winifred Reinger,ENGINEER +Marcella Bahringer,ENGINEER +Rhea Kohler,ENGINEER +Alia McCullough,ENGINEER +Mr. Israel Gulgowski,ENGINEER +Jana Wilkinson,ENGINEER +Marjory Fay,MANAGER +Alena Mueller,ENGINEER +Kristian Keebler,ENGINEER +Katheryn Dietrich,MANAGER +Mya Grady,MANAGER +Kyra Heidenreich V,ENGINEER +Dr. Cortez Thiel,MANAGER +Shyanne Hirthe,ENGINEER +Herta Mohr,ENGINEER +Winfield Thompson,ENGINEER +Miss Bette Dooley,MANAGER +Mrs. Freida Shanahan,ENGINEER +Sunny Towne,MANAGER +Kayley Schneider,ENGINEER +Anderson Hagenes,MANAGER +Barrett Paucek Jr.,MANAGER +Lillian Koss,ENGINEER +Lance Zieme,ENGINEER +Van Hackett,ENGINEER +Cullen Schamberger,ENGINEER +Arvel Stanton,MANAGER +Nedra Goldner,MANAGER +Ms. Zetta Lindgren,MANAGER +Faye Ledner,ENGINEER +Trystan Hilll PhD,MANAGER +Arnold Hermann Jr.,ENGINEER +Hank Towne,MANAGER +Monroe Schmeler,MANAGER +Genesis Wintheiser II,ENGINEER +Angie O'Reilly,MANAGER +Deshawn Reinger,MANAGER +Mrs. Molly Lowe,ENGINEER +Kimberly Osinski,MANAGER +Napoleon Sauer,ENGINEER +Leonardo Champlin,MANAGER +Anita Bartell,MANAGER +Mrs. Jennifer Buckridge,MANAGER +Patrick Gulgowski,MANAGER +Miss Brooks Christiansen,MANAGER +Ms. Alejandra Shields,ENGINEER +Callie Lynch,ENGINEER +Hyman Bruen,ENGINEER +Ms. Lera Grant,ENGINEER +Laney West V,MANAGER +Shyanne Price,ENGINEER +Leanna Schoen,ENGINEER +Clement Bayer,ENGINEER +Mrs. Colt Kozey,MANAGER +Dr. Logan Dickinson,ENGINEER +Valentin Torp,MANAGER +Kathlyn Bechtelar,MANAGER +Vita Pollich,ENGINEER +Benedict Flatley,MANAGER +Dedrick Corkery V,MANAGER +Shea Kohler,ENGINEER +Tiana Mertz,ENGINEER +Margarett Kunze,ENGINEER +Alan Bashirian,MANAGER +Dr. Precious Murazik,MANAGER +Ms. Karine Langosh,ENGINEER +Letha Skiles,ENGINEER +Nikko Dooley,ENGINEER +Filomena McKenzie,ENGINEER +Rosario Grant Sr.,ENGINEER +Gonzalo Douglas V,ENGINEER +Lempi Pollich,ENGINEER +Candida O'Reilly Sr.,ENGINEER +Dena Lind,ENGINEER +Blair Renner,MANAGER +Imani Roob,MANAGER +Miss Drake Johns,MANAGER +Murl Jacobi,MANAGER +Nicolette Prohaska,MANAGER +Leif Quigley,MANAGER +Hugh Gleichner III,MANAGER +Neil Witting,MANAGER +Ivah Moore,ENGINEER +Amira Bruen,ENGINEER +Loy Kerluke,ENGINEER +Cleta Berge,MANAGER +Asa Schaden,ENGINEER +Marlin Nitzsche,ENGINEER +Mellie Hansen,ENGINEER +Pauline Willms,MANAGER +Giovanna Marquardt,MANAGER +Kristian Conroy IV,MANAGER +Aiyana Hagenes,ENGINEER +Melisa Barton Jr.,MANAGER +Robbie Bechtelar,MANAGER +Citlalli Lind,ENGINEER +Karlee Lubowitz,MANAGER +Isidro Jerde,ENGINEER +Conor Lemke,MANAGER +Murphy Rutherford,MANAGER +Omari Schultz,MANAGER +Selmer Labadie,MANAGER +Alverta Hilpert,MANAGER +Ali Dooley III,ENGINEER +Benjamin Lubowitz,MANAGER +Trenton Hilll,MANAGER +Bethel Carroll,ENGINEER +Nick Lang,MANAGER +Ms. Chase Graham,MANAGER +Melany Buckridge PhD,ENGINEER +Ursula McGlynn,ENGINEER +Jackie Kshlerin,MANAGER +Jarvis Langosh,ENGINEER +Bonnie Bednar,MANAGER +Simeon Dickinson,ENGINEER +Annamarie VonRueden MD,MANAGER +Ms. Hilton Hagenes,ENGINEER +Jaqueline D'Amore,MANAGER +Mario Bartell,MANAGER +Frances Kovacek,MANAGER +Avery Lakin,MANAGER +Brittany Flatley DDS,ENGINEER +Violette Sauer,MANAGER +Dorothy Farrell,ENGINEER +Miss Jordan Crooks,MANAGER +Jadyn West,MANAGER +Mrs. Johanna Borer,ENGINEER +Elyssa Crist,ENGINEER +Carli Kohler,MANAGER +Dasia Dare,ENGINEER +Lane Rath,MANAGER +Davion Kunze,ENGINEER +Vada Stoltenberg,ENGINEER +London Hagenes,ENGINEER +Albin Wintheiser,MANAGER +Mr. Eloise Jones,ENGINEER +Rashawn Bechtelar,MANAGER +Linwood Casper,ENGINEER +Mr. Phyllis O'Reilly,MANAGER +Carrie Franecki,MANAGER +Mikel Daugherty I,MANAGER +Jorge Connelly IV,MANAGER +Victor Cummings,MANAGER +Felton Kris,MANAGER +Barney Klein,MANAGER +Verdie Strosin,MANAGER +Izabella Vandervort DDS,ENGINEER +Philip Hodkiewicz,MANAGER +Mr. Carol Orn,MANAGER +Ursula Cormier,MANAGER +Ellen Hudson,ENGINEER +Bobby Conn II,ENGINEER +Mathilde Bayer,ENGINEER +Ms. Marcus Ferry,ENGINEER +Tyshawn Volkman,MANAGER +Ladarius Predovic,ENGINEER +Ally Parisian,MANAGER +Briana Reinger,MANAGER +Piper Kutch,MANAGER +Armand Ratke,MANAGER +Stephon McLaughlin DDS,ENGINEER +Cordell Cole,ENGINEER +Earl Altenwerth,ENGINEER +Garrison Lang Jr.,MANAGER +Ahmad Heaney,ENGINEER +Jed Pollich,MANAGER +Hudson Wyman,MANAGER +Dena Crist DVM,ENGINEER +Gino Auer III,MANAGER +Miss Xavier Farrell,MANAGER +Lawrence Considine,ENGINEER +Coby Lesch,ENGINEER +Hardy Mohr,MANAGER +Dr. Tamara Ryan,MANAGER +Alia Quigley PhD,ENGINEER +Noelia Bergnaum,ENGINEER +Dakota Brown,ENGINEER +Elmo Rogahn,ENGINEER +Roxanne Weimann,MANAGER +Gay Langworth,MANAGER +Ellis Ledner,ENGINEER +Weston Murazik,ENGINEER +Josefa Sauer,MANAGER +Ilene Wyman,MANAGER +Nia Gottlieb,MANAGER +Crawford Wehner,MANAGER +Brenna Ritchie,MANAGER +Ms. Mariah Hudson,MANAGER +Tyra Schneider Sr.,MANAGER +Andreane Johns,MANAGER +Mrs. Mabel Rice,ENGINEER +Emelia Jaskolski PhD,ENGINEER +Spencer Cole II,ENGINEER +Doris Stokes,MANAGER +Lilian Erdman,ENGINEER +Ms. Ramona Torp,MANAGER +Ms. Lauryn Stark,MANAGER +Israel Greenholt,ENGINEER +Ms. Boris Leannon,MANAGER +Pearlie Swaniawski,MANAGER +Delores Kilback,MANAGER +Mariam Schultz,ENGINEER +Dimitri Mueller IV,MANAGER +Maud Beahan,MANAGER +Fletcher Predovic DVM,ENGINEER +Mrs. Joanne Aufderhar,ENGINEER +Miss Paul Lowe,ENGINEER +Johnpaul Swift,MANAGER +Miss Rowena Pouros,ENGINEER +Benjamin Jenkins,ENGINEER +Erwin Jenkins,MANAGER +Ms. Zula Turner,ENGINEER +Rhiannon Lind,MANAGER +Mrs. Garth Labadie,MANAGER +Mia King,MANAGER +Ewald Cronin,ENGINEER +Carrie Roob III,MANAGER +Clementina Schmeler,MANAGER +Stewart Sipes II,ENGINEER +Katelin D'Amore,MANAGER +Verlie Wiegand,MANAGER +Marie Schaefer,ENGINEER +Tillman Boehm,ENGINEER +Jacklyn Kohler,MANAGER +Katrine Bruen,MANAGER +Lisa Gaylord,ENGINEER +Virginia Ruecker,ENGINEER +Mrs. Garnett Christiansen,ENGINEER +Anderson Weissnat,ENGINEER +Marie Armstrong,ENGINEER +Prudence Fahey V,ENGINEER +Bria Medhurst,MANAGER +Ms. Dewitt Bernhard,ENGINEER +Stanford Miller,MANAGER +Freddie Treutel,MANAGER +Oceane Bayer,MANAGER +Ms. Adalberto Lindgren,MANAGER +Meagan Bartoletti,MANAGER +Wilhelm Kutch,ENGINEER +Khalid Farrell Sr.,MANAGER +Ms. Allison Zemlak,ENGINEER +Judson Rodriguez MD,MANAGER +Mr. Alena Stanton,MANAGER +Kaylin Kohler,ENGINEER +Melany Price,ENGINEER +Palma Brekke,MANAGER +Ozella Larson,MANAGER +Earnestine Sanford,ENGINEER +Kathryne Tromp,ENGINEER +Ted Abernathy,MANAGER +Nelle Waters,ENGINEER +Dawn Kautzer,ENGINEER +Ms. Itzel Breitenberg,ENGINEER +Meta Gibson,MANAGER +Haven Nitzsche,ENGINEER +Antonetta Kilback I,MANAGER +Kiara Zboncak,MANAGER +Leola Kris,ENGINEER +Mr. Conrad Hills,MANAGER +Alize Rogahn,ENGINEER +Rudy Hamill,MANAGER +Ms. Celestino Turcotte,MANAGER +Ms. Annetta Stracke,MANAGER +Hailie Hudson,ENGINEER +Mrs. Deven Moen,MANAGER +Callie Larson,MANAGER +Quentin Morar,ENGINEER +Antonietta Kuhlman II,MANAGER +Cristal Shanahan DVM,MANAGER +Cristopher Boyer,ENGINEER +Keely Larkin,ENGINEER +Royce Berge,ENGINEER +Benjamin Hilll,ENGINEER +Rashawn Bogan,MANAGER +Ted Collier,MANAGER +Alene Corwin,MANAGER +David Hodkiewicz,MANAGER +Garland Kuhic,MANAGER +Sonya Wilderman,MANAGER +Quinn Bradtke Jr.,MANAGER +Ellen Cummerata,ENGINEER +Mason Beatty,MANAGER +Camylle Muller,MANAGER +Hadley Upton,ENGINEER +Keara Pfeffer,ENGINEER +Angie Walsh,MANAGER +Earl Cummings,MANAGER +Ephraim Marks,ENGINEER +Orval Reichert DDS,ENGINEER +Katheryn Gleichner,ENGINEER +Jalyn Fay I,ENGINEER +Virginia Keebler DVM,ENGINEER +Raphael Leffler,ENGINEER +Juliana Stokes,MANAGER +Casper Herman,MANAGER +Vladimir Reilly,MANAGER +Erin Okuneva,MANAGER +Martine White,MANAGER +Tristian Mertz,MANAGER +Mr. Sammy Schmitt,ENGINEER +Alec Schuster,MANAGER +Ms. Lorenza Walsh,ENGINEER +Eldora Mayert,ENGINEER +Justina Breitenberg,MANAGER +Mariela Grady Jr.,ENGINEER +Kevon Baumbach,MANAGER +Wendell Hayes,ENGINEER +Pat Aufderhar,ENGINEER +Bart Senger,MANAGER +Kaitlyn Hahn,ENGINEER +Mrs. Else Kozey,MANAGER +Mr. Ashton Batz,ENGINEER +Lilly Koepp,ENGINEER +Mrs. Alfredo Cormier,MANAGER +Gail Swaniawski DVM,ENGINEER +Mrs. Valentina Wilderman,ENGINEER +Paxton Doyle,ENGINEER +Jarret Block PhD,MANAGER +Arnaldo Blanda,MANAGER +Aiden Orn,MANAGER +Florine West,MANAGER +Sincere Harber,MANAGER +Joan Ziemann,ENGINEER +Katelyn Schultz,ENGINEER +Maximus Gleichner,MANAGER +Elenor Schuster,MANAGER +Marcelino Kautzer,ENGINEER +Lea Schulist Sr.,ENGINEER +Jeanne Carter MD,MANAGER +Kayleigh Goldner DDS,ENGINEER +Hilario Denesik I,MANAGER +Shirley Reichert,MANAGER +Kris Dickens,ENGINEER +Gene Frami,MANAGER +Sadye Jacobson,MANAGER +Buck Cremin,ENGINEER +Coty Lesch,ENGINEER +Dr. Kim Mertz,ENGINEER +Randy Sanford,MANAGER +Levi Kirlin,MANAGER +Davin Yundt,ENGINEER +Enola Bins,ENGINEER +Trent Kuvalis,ENGINEER +Jake Powlowski,ENGINEER +Ms. Ashlee Emmerich,MANAGER +Hannah Davis,ENGINEER +Wayne Champlin,ENGINEER +Nikki Conn Jr.,MANAGER +Carli Bauch,ENGINEER +Norbert Feest,MANAGER +Robbie Wintheiser,ENGINEER +Leta Abshire,ENGINEER +Fannie Walker,ENGINEER +Heber Wilkinson,MANAGER +Willie Bernier III,MANAGER +Orlando Price,ENGINEER +Brandt Schowalter,MANAGER +Mohammed Stokes,ENGINEER +Isai Mraz,ENGINEER +Kadin Lemke,MANAGER +Maribel Jerde,MANAGER +Myrna Kessler,MANAGER +Meredith Tremblay,ENGINEER +Mr. Jerad Schneider,ENGINEER +Lenny Pfeffer,MANAGER +Carolyne Klocko DVM,MANAGER +Monica Schulist,ENGINEER +Anika Larson V,MANAGER +Domenick Pacocha,ENGINEER +Miss Harmon Pfannerstill,ENGINEER +Mr. Annabell Pouros,MANAGER +Dr. Brisa Stroman,MANAGER +Jade Stoltenberg,MANAGER +Miss Mario Wolff,ENGINEER +Ms. Savannah Gaylord,MANAGER +Dejah Jones,MANAGER +Hector Kulas,MANAGER +Graciela Goodwin,MANAGER +Jocelyn Sauer,MANAGER +Miss Lew Hansen,MANAGER +Fannie Fay DDS,ENGINEER +Dr. Jordan Klocko,ENGINEER +Kathlyn Lynch,MANAGER +Leann Botsford,ENGINEER +Ervin Larson,MANAGER +Allie Von,MANAGER +Johanna Kohler III,MANAGER +Hilbert Armstrong,ENGINEER +Tanner Balistreri IV,MANAGER +Abagail Shields,ENGINEER +Gia Cremin,ENGINEER +Mrs. Buford Oberbrunner,ENGINEER +Madelyn White,MANAGER +Abdullah Effertz,MANAGER +Reva Stark,ENGINEER +Camryn McKenzie,MANAGER +Juwan Pouros,MANAGER +Gene Cassin,MANAGER +Felicia Kunde,ENGINEER +Jeremie Anderson,MANAGER +Katheryn Hickle Jr.,MANAGER +Edwina Hamill IV,MANAGER +Adriana Cassin DVM,MANAGER +Nelda Rowe,ENGINEER +Rodrigo Kulas V,ENGINEER +Jaiden Williamson,MANAGER +Cristopher Williamson,MANAGER +Mr. Jay Krajcik,ENGINEER +Francesco Miller,MANAGER +Brenna Reinger,MANAGER +Mr. Mollie Stanton,MANAGER +Coby Schowalter,ENGINEER +Estefania Armstrong II,MANAGER +Aimee Nienow,ENGINEER +Kimberly Batz,ENGINEER +Miss Sienna Pfannerstill,ENGINEER +Johnathon Hammes,ENGINEER +Julien Hansen,MANAGER +Mrs. Emerson Waelchi,MANAGER +Malcolm Streich,MANAGER +Aurelio Lebsack,ENGINEER +Juana Grady,ENGINEER +Kiel Lakin,MANAGER +Sarai Keeling,ENGINEER +Emilia Crona,ENGINEER +Georgianna Kris,MANAGER +Maida Heller,MANAGER +Jena Feeney,ENGINEER +Mabelle Keeling,MANAGER +Chris Bergstrom,ENGINEER +Audrey Block DDS,ENGINEER +Louvenia Kuhn,ENGINEER +Thomas O'Keefe,MANAGER +Darby Klocko,MANAGER +Arlene Weimann,MANAGER +Corbin Jones MD,ENGINEER +Lamar Mraz,ENGINEER +Miss Onie Krajcik,MANAGER +Kamille Schaefer,MANAGER +Jack Borer,ENGINEER +Reese Heaney,MANAGER +Ilene Kovacek,ENGINEER +Trace Bailey,ENGINEER +Wava Donnelly,ENGINEER +Mona Lakin,MANAGER +Weldon Heaney,MANAGER +Norris Labadie,ENGINEER +Bridgette Brown,MANAGER +Osborne Kertzmann,MANAGER +Verlie Bruen,ENGINEER +Enrique Ullrich,ENGINEER +Dr. Asia Purdy,ENGINEER +Lindsey Predovic DDS,MANAGER +Maxine Mosciski,MANAGER +Sydni Stoltenberg,ENGINEER +Paige Buckridge,ENGINEER +Miss Laverne Dach,MANAGER +Murl Abshire,MANAGER +Lou Friesen,MANAGER +Keenan Fahey,ENGINEER +Ashleigh Schultz,ENGINEER +Mrs. Keshaun Lesch,ENGINEER +Jeffrey Langosh,ENGINEER +Mckenzie Boyle,ENGINEER +Hipolito Price PhD,MANAGER +Lesley Adams III,ENGINEER +Mya Howe,ENGINEER +Nick Kutch Sr.,MANAGER +Ms. Winfield Wilkinson,ENGINEER +Leopold Schulist,ENGINEER +Orval Prosacco,ENGINEER +Wilmer Mueller,MANAGER +Karina Batz,MANAGER +Luigi Abbott,MANAGER +Pamela Miller,MANAGER +Emelie Marquardt,ENGINEER +Zola Beier,MANAGER +Mr. Elva Ritchie,ENGINEER +Mrs. Otis Quitzon,MANAGER +Dr. Willow Jacobs,MANAGER +Cathryn Koss,MANAGER +Ms. Alivia Ernser,MANAGER +Timothy Mohr,ENGINEER +Mrs. Jaylan Wuckert,MANAGER +Emerald Waelchi,ENGINEER +Vernon Heathcote,MANAGER +Lavinia Ruecker,ENGINEER +Mr. Quinn Altenwerth,MANAGER +Alejandra Marks,MANAGER +Mr. Leo Wuckert,MANAGER +Jayce Schiller MD,MANAGER +Elenora Ebert Jr.,ENGINEER +Dr. Rose Wyman,MANAGER +Wade Orn,MANAGER +Iva Marks Sr.,MANAGER +Margaret Pouros,MANAGER +Barton Deckow,MANAGER +Miss Lesly Balistreri,ENGINEER +Mr. Jacquelyn Reynolds,ENGINEER +Doyle Heidenreich,MANAGER +Heidi Ruecker,ENGINEER +Mr. Alvis Moen,MANAGER +Dr. Garnet Brown,ENGINEER +Yolanda Beier,ENGINEER +Soledad Macejkovic,ENGINEER +Urban Lowe,ENGINEER +Devyn Schmidt,MANAGER +Barbara Flatley,MANAGER +Patsy Sanford PhD,ENGINEER +Mrs. Rubye Blanda,ENGINEER +Caleigh Klocko,ENGINEER +Kali Dietrich,MANAGER +Ms. Weldon Hudson,ENGINEER +Vallie Huel,ENGINEER +Sven O'Keefe III,ENGINEER +Gerardo Wehner Sr.,ENGINEER +Kyle Kirlin,MANAGER +Marianne Berge Jr.,ENGINEER +Ms. Cristal Connelly,MANAGER +Kailey Spinka,MANAGER +Jeremie Morar,MANAGER +Daija Lind,ENGINEER +Arvel McDermott,ENGINEER +Dr. Nicholas Gorczany,MANAGER +Anne Leuschke,MANAGER +Gerda Cronin,ENGINEER +Ms. Coty Rolfson,ENGINEER +Kareem Gerhold,ENGINEER +Mrs. Nico Mann,ENGINEER +Corbin Bartell,ENGINEER +Theresa Gulgowski,MANAGER +Carmelo Boyer,MANAGER +Elinore Schulist III,MANAGER +Katarina Schultz,MANAGER +Deven Rodriguez II,MANAGER +Miss Bruce Friesen,MANAGER +Marcelle Schowalter,MANAGER +Albertha Murphy PhD,MANAGER +Elmore Doyle,ENGINEER +Reymundo Jaskolski,ENGINEER +Stephania Swaniawski I,MANAGER +Stewart Veum,MANAGER +Nathanael Bartell,MANAGER +Retha Rempel,ENGINEER +Isidro Aufderhar,MANAGER +Florencio Mohr,MANAGER +Zella Weimann,ENGINEER +Khalid Macejkovic,ENGINEER +Geraldine Torp,ENGINEER +Presley Marks,ENGINEER +Mrs. Eve Bartoletti,ENGINEER +Corine Schimmel,MANAGER +Citlalli Goldner DDS,MANAGER +Zakary Botsford,MANAGER +Florida Reilly,ENGINEER +Mr. Patsy Doyle,MANAGER +Emily Hayes II,ENGINEER +Dr. Johann Turcotte,ENGINEER +Dr. Darion Dietrich,ENGINEER +Norris Brekke,MANAGER +Janessa Marquardt,MANAGER +Felicita Wintheiser MD,MANAGER +Melyssa Muller,ENGINEER +Vivienne Weissnat DDS,ENGINEER +Ford Gerlach,ENGINEER +Keenan Kertzmann,ENGINEER +Tobin Goyette,ENGINEER +Cecilia Green,MANAGER +Abe Fisher,MANAGER +Mrs. Annabell Morissette,MANAGER +Danny Kautzer III,MANAGER +Gerard Cruickshank,ENGINEER +Joy Okuneva DDS,MANAGER +Ezequiel Macejkovic,ENGINEER +Vernie Bradtke IV,ENGINEER +Trycia Muller,ENGINEER +Clotilde Ankunding,ENGINEER +Mr. Chaya Abshire,ENGINEER +Hanna Roob,MANAGER +Ronny Dietrich,ENGINEER +Derek Durgan DVM,MANAGER +Demetrius West,MANAGER +Macey Nikolaus,MANAGER +Edison Gottlieb III,MANAGER +Bo Collins,ENGINEER +Michaela Pagac PhD,MANAGER +Mireille Kunde I,ENGINEER +Duncan Kulas,MANAGER +Mrs. Xzavier Smitham,ENGINEER +Mr. Adrianna Baumbach,MANAGER +Shad Rolfson,MANAGER +Mr. Dimitri Baumbach,MANAGER +Samara Schultz,MANAGER +Mrs. Brant Kautzer,MANAGER +Tierra Greenholt,ENGINEER +Otho Kub,MANAGER +Ana Harber,MANAGER +Ted Mertz Sr.,ENGINEER +Uriel Zieme,MANAGER +Mr. Adaline Wolff,ENGINEER +Mrs. Maurice Senger,MANAGER +Ada Gleason,MANAGER +Edwina Bernier DVM,ENGINEER +Elva Homenick,ENGINEER +Mrs. Shane Powlowski,MANAGER +Obie Nikolaus,MANAGER +Ottis Jakubowski,MANAGER +Mr. Armand Leannon,ENGINEER +Jaime Kuvalis,ENGINEER +Loyce VonRueden Jr.,ENGINEER +Evangeline Johns,MANAGER +Federico Halvorson,MANAGER +Sylvester Gerlach,MANAGER +Ashly Wunsch V,MANAGER +Rowland Miller,MANAGER +Bryon Kunde,MANAGER +Denis Ernser,ENGINEER +Jovanny O'Reilly DVM,ENGINEER +Lazaro Hermiston,MANAGER +Kelly Stehr,ENGINEER +Oda Fadel,ENGINEER +Percival Armstrong,ENGINEER +Caleigh Schimmel,MANAGER +Tyrique Pfeffer,ENGINEER +Adell Leuschke,ENGINEER +Dr. Cade Farrell,ENGINEER +Gisselle Doyle,MANAGER +Lily Reinger,MANAGER +Jeffrey Gleason,ENGINEER +Tad Huel,ENGINEER +Connor Conn,MANAGER +Mr. Cathrine Casper,ENGINEER +Dr. Beryl Rempel,MANAGER +Carlie Steuber,MANAGER +Rose Frami IV,ENGINEER +Mr. Tyrel Pagac,MANAGER +Morton Trantow,ENGINEER +Lola Ortiz,MANAGER +Kelton Champlin,MANAGER +Owen Mayert,ENGINEER +Johnny Witting,MANAGER +Thea Rolfson,MANAGER +Reanna Schmidt,ENGINEER +Ian Stehr,MANAGER +Mr. Patsy Purdy,MANAGER +Brady Ritchie,ENGINEER +Thea Effertz,MANAGER +Gerry Veum,ENGINEER +Corene Adams,MANAGER +Julian Kutch,MANAGER +Mrs. Joe Connelly,ENGINEER +Adolphus Paucek,MANAGER +Jasmin Ledner II,ENGINEER +Dr. Osbaldo Beatty,ENGINEER +Dr. Mckenna Haag,MANAGER +Abdiel Connelly DVM,ENGINEER +Liliana Baumbach III,MANAGER +Willard Kuvalis V,ENGINEER +Carolyn Jaskolski Jr.,MANAGER +Reta Franecki,ENGINEER +Percival O'Kon,ENGINEER +Kamryn Rath,MANAGER +Hailey Dooley,MANAGER +Mrs. Brycen West,ENGINEER +Margarette Miller,MANAGER +Cristian Pagac,MANAGER +Rosalee Bechtelar,MANAGER +Lessie Lesch,MANAGER +Iva Hegmann,MANAGER +Hallie Schroeder,MANAGER +Mr. Lola Volkman,ENGINEER +Arianna Wolf DDS,MANAGER +Elliot Trantow,MANAGER +Darrion Rath PhD,ENGINEER +Coralie Effertz V,ENGINEER +Ms. Corrine Effertz,ENGINEER +Ellie Keebler,ENGINEER +Tyrese Pfeffer,ENGINEER +Jayce Roberts,MANAGER +Isobel Veum,ENGINEER +Raphaelle Breitenberg,ENGINEER +Maudie Labadie I,ENGINEER +Rosario Langosh MD,ENGINEER +Raheem Mohr,MANAGER +Avery Lind,ENGINEER +Nichole Waters,ENGINEER +Blaise Gislason I,MANAGER +Everette D'Amore,ENGINEER +Darwin Conroy,MANAGER +Abdullah Heathcote,ENGINEER +Burnice Treutel,MANAGER +Libbie O'Hara,ENGINEER +Rowan Will,MANAGER +Gudrun Gleason,ENGINEER +Fannie Quitzon,MANAGER +Terence Gutkowski,ENGINEER +Tyshawn Rowe,MANAGER +Jaylan Sanford,MANAGER +Camille Schaden DVM,MANAGER +Ms. Blaze Emmerich,MANAGER +Sonny Stoltenberg,ENGINEER +Elsie Jacobson,MANAGER +London Jacobs,MANAGER +Mr. Hassie Kuhn,ENGINEER +Raul Bogan MD,ENGINEER +Adrian Abshire,MANAGER +Golden Kreiger,MANAGER +Deven Stiedemann I,MANAGER +Hilario Koepp PhD,MANAGER +Maynard Herzog,MANAGER +Nathaniel Torp,MANAGER +Courtney Strosin,MANAGER +Emely Lowe,ENGINEER +Vilma Weber,ENGINEER +Ms. Carlee Littel,ENGINEER +Hayden Mills,ENGINEER +Ervin Schimmel,ENGINEER +Gino Ortiz,ENGINEER +Amani Conroy,MANAGER +Korbin Lowe,MANAGER +Turner Bogan I,ENGINEER +Ms. Jabari Bauch,MANAGER +Mrs. Breanne Morissette,ENGINEER +Crystel Doyle,MANAGER +Isabel VonRueden,ENGINEER +Dayne Cremin,ENGINEER +Waino Armstrong,MANAGER +Deborah Armstrong,MANAGER +Ashlynn Mante DVM,ENGINEER +Karlie Pollich Jr.,ENGINEER +Maeve Schroeder,MANAGER +Hanna Fadel,ENGINEER +Delphia O'Hara,MANAGER +Jamir Hammes,ENGINEER +Nigel Ortiz,ENGINEER +Pauline Ritchie,MANAGER +Nicholaus Toy,ENGINEER +Freddy Okuneva,MANAGER +Brionna Fritsch,ENGINEER +Maiya Mills,ENGINEER +Alia Hoeger PhD,MANAGER +Alvina Mertz,ENGINEER +Raymundo Hintz,ENGINEER +Zack Stamm,ENGINEER +Dayne Klocko,MANAGER +Kyla Cremin,ENGINEER +Izabella Bernhard,ENGINEER +Zena Yundt,ENGINEER +Daron Schuppe,MANAGER +Mr. Amira Marvin,MANAGER +Boris Morar,MANAGER +Esperanza Batz,ENGINEER +Dortha Macejkovic I,MANAGER +Porter Dach V,ENGINEER +Kailyn Flatley I,MANAGER +Celine O'Keefe,MANAGER +Obie Rodriguez,MANAGER +Cade Gorczany,ENGINEER +Myles Shanahan,ENGINEER +Jayne Wiza,ENGINEER +Julius Huel,MANAGER +Ms. Rowena Kihn,ENGINEER +Ena Wehner,MANAGER +Clovis Cartwright,MANAGER +Mr. Marcelo D'Amore,MANAGER +Meggie Prosacco,ENGINEER +Lisa Schamberger PhD,ENGINEER +Mrs. Lyda Bayer,MANAGER +Newell Hettinger,MANAGER +Melany Wolf,MANAGER +Emil Schaefer,MANAGER +Samson Trantow,MANAGER +Maida Marquardt,ENGINEER +Johnpaul Howe MD,MANAGER +Mrs. Adah Lubowitz,ENGINEER +Ms. Imelda Kohler,MANAGER +Manuela Frami I,ENGINEER +Noelia Padberg,MANAGER +Una Eichmann DDS,ENGINEER +Elta Nolan,ENGINEER +Jaron Wyman,ENGINEER +Kayla Windler Sr.,MANAGER +Mrs. Zetta Stiedemann,MANAGER +Dr. Abner Adams,MANAGER +Brenden Ortiz,MANAGER +German Funk,ENGINEER +Mr. Liliane Konopelski,MANAGER +Jarrett Morar,MANAGER +Parker Huels,MANAGER +Mrs. Alvah Bayer,ENGINEER +Wilhelm Parker Jr.,ENGINEER +Leo Mertz,ENGINEER +Corine Hills,ENGINEER +Coy Raynor Sr.,ENGINEER +Mallie Streich DVM,ENGINEER +Daisy Hoeger,MANAGER +Michelle Hickle,ENGINEER +Nolan Douglas,ENGINEER +Vivian Bernier,ENGINEER +Brigitte Toy,ENGINEER +Aniyah Schoen,ENGINEER +Emmie Bins,ENGINEER +Mazie Weimann,MANAGER +Carole Aufderhar,ENGINEER +Bernhard O'Kon,ENGINEER +Flavio Moore Sr.,MANAGER +Justina Wuckert,ENGINEER +Meredith Jones,ENGINEER +Gene Champlin,MANAGER +Clare Fay,MANAGER +Lesly Johnston II,MANAGER +Cristian Kling,MANAGER +Candido Littel,MANAGER +Mrs. Gregory Ritchie,ENGINEER +Lucio Sawayn,MANAGER +Derick Rath DVM,MANAGER +Gabriella Dietrich,ENGINEER +Lula Spencer DVM,ENGINEER +Horacio Kulas,ENGINEER +Davin Vandervort DDS,ENGINEER +Ms. Avery Wisoky,ENGINEER +Talon Williamson MD,MANAGER +Gerald Hahn,MANAGER +Ettie Yost,MANAGER +Abdullah Mosciski,ENGINEER +Mrs. Marielle Bosco,ENGINEER +Kory Batz,MANAGER +Noelia Kovacek,ENGINEER +Kyleigh Nienow,MANAGER +Alize Lind,ENGINEER +Ellsworth Altenwerth,ENGINEER +Domenic Mayer,ENGINEER +Ms. Geovanny Satterfield,ENGINEER +Ella Daniel,MANAGER +Kylee Bogisich PhD,ENGINEER +Ryder Wilkinson Sr.,MANAGER +Marina Schaefer,ENGINEER +Ms. Paige Bartell,MANAGER +Mitchel Murray,ENGINEER +Tyler Quigley,MANAGER +Veronica Kreiger,ENGINEER +Halie Goldner,ENGINEER +Ryder Lakin,ENGINEER +Chloe Legros,ENGINEER +Dariana O'Conner,ENGINEER +Era Bins Jr.,ENGINEER +Laila Reichert,MANAGER +Dedrick Kuhic V,ENGINEER +Haylee Price Jr.,ENGINEER +Callie Shields,MANAGER +Jarrod Fahey,MANAGER +Earlene Cremin,ENGINEER +Ellie Bergstrom,MANAGER +Armando Grady,ENGINEER +Dr. Lamar Hessel,ENGINEER +Joe Runolfsson Sr.,ENGINEER +Manley Oberbrunner,MANAGER +Meta Weissnat II,ENGINEER +Dagmar Batz IV,ENGINEER +Susie Bayer,ENGINEER +Randi Howell,ENGINEER +Joanne Rau,MANAGER +Buck Stark,ENGINEER +Shane Donnelly,ENGINEER +Quincy Casper V,ENGINEER +Lafayette Grimes,MANAGER +Mrs. Jody Beer,ENGINEER +Miss Corene Schamberger,ENGINEER +Dr. Jesse Baumbach,ENGINEER +Brenna Quigley Jr.,MANAGER +Ms. Viviane Bins,ENGINEER +Edgar Johnson,MANAGER +Mr. Tracy Beier,ENGINEER +Juvenal Ortiz,ENGINEER +Dr. Nat Pagac,MANAGER +Julio Mitchell,ENGINEER +Clarissa Mraz Jr.,ENGINEER +Dustin Grady,MANAGER +Brennon Bayer,ENGINEER +Mrs. Birdie Nienow,MANAGER +Randal Sauer Sr.,ENGINEER +Verda Kozey,ENGINEER +Chesley Hickle,ENGINEER +Miss Rico Block,ENGINEER +Gaetano Lindgren,MANAGER +Hope Hauck,ENGINEER +Percival O'Connell,ENGINEER +Melyna Leuschke,MANAGER +Adan Collins,MANAGER +Daryl Bashirian,ENGINEER +Kara Welch,MANAGER +Norberto Swift,ENGINEER +Effie Champlin Jr.,ENGINEER +Dr. Julia Metz,MANAGER +Janice Witting,MANAGER +Bruce Eichmann,MANAGER +Isobel Swift,ENGINEER +Earnestine Mayer MD,MANAGER +Michele Bashirian,ENGINEER +Janick Crona,ENGINEER +Hank Fisher III,MANAGER +Miss Aliya Skiles,ENGINEER +Herbert Orn,MANAGER +Aglae Baumbach,ENGINEER +Gayle Carter,ENGINEER +Creola Kautzer,MANAGER +Theresa Hauck,MANAGER +Ms. Patience Wintheiser,MANAGER +Sebastian Rutherford DDS,ENGINEER +Ara Pollich I,ENGINEER +Carlos Baumbach,MANAGER +Hulda Schroeder DVM,ENGINEER +Stanton Torp,MANAGER +Ceasar Franecki,MANAGER +Lelah Miller,ENGINEER +Wyman Schultz,MANAGER +Mae Harris V,MANAGER +Hortense Koelpin,ENGINEER +Wilmer Deckow,ENGINEER +Zaria Ferry,ENGINEER +Pierre Cronin,ENGINEER +Ms. Brenna Leffler,ENGINEER +Dr. Keara Price,ENGINEER +Jane Schroeder,MANAGER +Reymundo Heathcote,MANAGER +Elton Schiller II,MANAGER +Irma Blanda,MANAGER +Mireya Turner,MANAGER +Dawson Streich,MANAGER +Gianni Cassin,MANAGER +Johnathan Kuhic V,MANAGER +Lacey Sawayn,ENGINEER diff --git a/internal/service/comprehend/test-fixtures/generate/entity_recognizer/main.go b/internal/service/comprehend/test-fixtures/generate/entity_recognizer/main.go new file mode 100644 index 00000000000..3247cfdeedf --- /dev/null +++ b/internal/service/comprehend/test-fixtures/generate/entity_recognizer/main.go @@ -0,0 +1,99 @@ +//go:build generate +// +build generate + +package main + +import ( + "encoding/csv" + "fmt" + "log" + "math/rand" + "os" + "strconv" + "strings" + + "syreclabs.com/go/faker" +) + +func main() { + var entities = []string{ + "ENGINEER", + "MANAGER", + } + + var sentences = []string{ + "%[1]s is a %[2]s in the high tech industry.", + "%[1]s has been a %[2]s for 14 years.", + "Our latest new employee, %[1]s, has been a %[2]s in the industry for 4 years.", + "Announcing %[2]s %[1]s.", + "Help me welcome our newest %[2]s, %[1]s.", + "%[1]s is retiring as a %[2]s.", + "%[1]s has been an %[2]s for over a decade.", + "%[1]s is a %[2]s with Example Corp.", + "%[1]s will be the new %[2]s for the team.", + "%[1]s, an %[2]s, will be presenting the award.", + "%[1]s joins us as an %[2]s on the Example project.", + "%[1]s is a %[2]s.", + } + + log.SetFlags(0) + + seed := int64(1) // Default rand seed + rand.Seed(seed) + faker.Seed(seed) + + entitiesFile, err := os.OpenFile("./test-fixtures/entity_recognizer/entitylist.csv", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0600) + if err != nil { + log.Fatalf("error opening file %q: %s", "entitylist.csv", err) + } + defer closeFile(entitiesFile, "entitylist.csv") + + if _, err := fmt.Fprintln(entitiesFile, "Text,Type"); err != nil { + log.Fatalf("error writing to file %q: %s", "entitylist.csv", err) + } + + documentFile, err := os.OpenFile("./test-fixtures/entity_recognizer/documents.txt", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0600) + if err != nil { + log.Fatalf("error opening file %q: %s", "documents.txt", err) + } + defer closeFile(documentFile, "documents.txt") + + annotationsFile, err := os.OpenFile("./test-fixtures/entity_recognizer/annotations.csv", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0600) + if err != nil { + log.Fatalf("error opening file %q: %s", "annotations.csv", err) + } + defer closeFile(annotationsFile, "annotations.csv") + annotationsWriter := csv.NewWriter(annotationsFile) + if err := annotationsWriter.Write([]string{"File", "Line", "Begin Offset", "End Offset", "Type"}); err != nil { + log.Fatalf("error writing to file %q: %s", "annotations.csv", err) + } + + for i := 0; i < 1000; i++ { + name := faker.Name().Name() + entity := entities[rand.Intn(len(entities))] + + if _, err := fmt.Fprintf(entitiesFile, "%s,%s\n", name, entity); err != nil { + log.Fatalf("error writing to file %q: %s", "entitylist.csv", err) + } + + sentence := sentences[rand.Intn(len(sentences))] + line := fmt.Sprintf(sentence, name, strings.ToLower(entity)) + if _, err := fmt.Fprintln(documentFile, line); err != nil { + log.Fatalf("error writing to file %q: %s", "documents.txt", err) + } + + offset := strings.Index(line, name) + end := offset + len(name) + if err := annotationsWriter.Write([]string{"documents.txt", strconv.Itoa(i), strconv.Itoa(offset), strconv.Itoa(end), entity}); err != nil { + log.Fatalf("error writing to file %q: %s", "annotations.csv", err) + } + } + + annotationsWriter.Flush() +} + +func closeFile(f *os.File, name string) { + if err := f.Close(); err != nil { + log.Fatalf("error closing file %q: %s", name, err) + } +} diff --git a/internal/service/comprehend/validate.go b/internal/service/comprehend/validate.go new file mode 100644 index 00000000000..947a8de8b4b --- /dev/null +++ b/internal/service/comprehend/validate.go @@ -0,0 +1,72 @@ +package comprehend + +import ( + "fmt" + "regexp" + + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +const ( + modelIdentifierMaxLen = 63 // Documentation says 256, Console says 63 + modelIdentifierPrefixMaxLen = modelIdentifierMaxLen - resource.UniqueIDSuffixLength +) + +var validModelName = validIdentifier +var validModelVersionName = validation.Any( // nosemgrep:ci.avoid-string-is-empty-validation + validation.StringIsEmpty, + validIdentifier, +) +var validModelVersionNamePrefix = validIdentifierPrefix + +var validIdentifier = validation.All( + validation.StringLenBetween(1, modelIdentifierMaxLen), + validIdentifierPattern, +) + +var validIdentifierPrefix = validation.All( + validation.StringLenBetween(1, modelIdentifierPrefixMaxLen), + validIdentifierPattern, +) + +var validIdentifierPattern = validation.StringMatch(regexp.MustCompile(`^[[:alnum:]-]+$`), "must contain A-Z, a-z, 0-9, and hypen (-)") + +var validateKMSKey = validation.Any( + validateKMSKeyId, + validateKMSKeyARN, +) + +var validateKMSKeyId = validation.StringMatch(regexp.MustCompile("^"+verify.UUIDRegexPattern+"$"), "must be a KMS Key ID") + +func validateKMSKeyARN(v any, k string) (ws []string, errors []error) { + value, ok := v.(string) + if !ok { + errors = append(errors, fmt.Errorf("expected type of %s to be string", k)) + return + } + + if value == "" { + return + } + + parsedARN, err := arn.Parse(value) + if err != nil { + errors = append(errors, fmt.Errorf("%q (%s) is an invalid ARN: %s", k, value, err)) + return + } + + if parsedARN.Service != "kms" { + errors = append(errors, fmt.Errorf("%q (%s) is not a valid KMS Key ARN: %s", k, value, err)) + return + } + + if id := kmsKeyIdFromARNResource(parsedARN.Resource); id == "" { + errors = append(errors, fmt.Errorf("%q (%s) is not a valid KMS Key ARN: %s", k, value, err)) + return + } + + return +} diff --git a/internal/service/comprehend/validate_test.go b/internal/service/comprehend/validate_test.go new file mode 100644 index 00000000000..a7d3430e038 --- /dev/null +++ b/internal/service/comprehend/validate_test.go @@ -0,0 +1,51 @@ +package comprehend + +import ( + "testing" +) + +func TestValidateKMSKeyARN(t *testing.T) { + testcases := map[string]struct { + in any + valid bool + }{ + "kms key id": { + in: "arn:aws:kms:us-west-2:123456789012:key/57ff7a43-341d-46b6-aee3-a450c9de6dc8", // lintignore:AWSAT003,AWSAT005 + valid: true, + }, + "kms non-key id": { + in: "arn:aws:kms:us-west-2:123456789012:something/else", // lintignore:AWSAT003,AWSAT005 + valid: false, + }, + "non-kms arn": { + in: "arn:aws:iam::123456789012:user/David", // lintignore:AWSAT005 + valid: false, + }, + "not an arn": { + in: "not an arn", + valid: false, + }, + "not a string": { + in: 123, + valid: false, + }, + } + + for name, testcase := range testcases { + t.Run(name, func(t *testing.T) { + aWs, aEs := validateKMSKeyARN(testcase.in, "field") + if len(aWs) != 0 { + t.Errorf("expected no warnings, got %v", aWs) + } + if testcase.valid { + if len(aEs) != 0 { + t.Errorf("expected no errors, got %v", aEs) + } + } else { + if len(aEs) == 0 { + t.Error("expected errors, got none") + } + } + }) + } +} diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index aa510f820ab..61220b9cb2b 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -1333,8 +1333,8 @@ func FindNetworkACLEntryByThreePartKey(conn *ec2.EC2, naclID string, egress bool return nil, &resource.NotFoundError{} } -func FindNetworkInterface(conn *ec2.EC2, input *ec2.DescribeNetworkInterfacesInput) (*ec2.NetworkInterface, error) { - output, err := FindNetworkInterfaces(conn, input) +func FindNetworkInterfaceWithContext(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeNetworkInterfacesInput) (*ec2.NetworkInterface, error) { + output, err := FindNetworkInterfacesWithContext(ctx, conn, input) if err != nil { return nil, err @@ -1351,10 +1351,10 @@ func FindNetworkInterface(conn *ec2.EC2, input *ec2.DescribeNetworkInterfacesInp return output[0], nil } -func FindNetworkInterfaces(conn *ec2.EC2, input *ec2.DescribeNetworkInterfacesInput) ([]*ec2.NetworkInterface, error) { +func FindNetworkInterfacesWithContext(ctx context.Context, conn *ec2.EC2, input *ec2.DescribeNetworkInterfacesInput) ([]*ec2.NetworkInterface, error) { var output []*ec2.NetworkInterface - err := conn.DescribeNetworkInterfacesPages(input, func(page *ec2.DescribeNetworkInterfacesOutput, lastPage bool) bool { + err := conn.DescribeNetworkInterfacesPagesWithContext(ctx, input, func(page *ec2.DescribeNetworkInterfacesOutput, lastPage bool) bool { if page == nil { return !lastPage } @@ -1383,11 +1383,15 @@ func FindNetworkInterfaces(conn *ec2.EC2, input *ec2.DescribeNetworkInterfacesIn } func FindNetworkInterfaceByID(conn *ec2.EC2, id string) (*ec2.NetworkInterface, error) { + return FindNetworkInterfaceByIDWithContext(context.Background(), conn, id) +} + +func FindNetworkInterfaceByIDWithContext(ctx context.Context, conn *ec2.EC2, id string) (*ec2.NetworkInterface, error) { input := &ec2.DescribeNetworkInterfacesInput{ NetworkInterfaceIds: aws.StringSlice([]string{id}), } - output, err := FindNetworkInterface(conn, input) + output, err := FindNetworkInterfaceWithContext(ctx, conn, input) if err != nil { return nil, err @@ -1404,6 +1408,10 @@ func FindNetworkInterfaceByID(conn *ec2.EC2, id string) (*ec2.NetworkInterface, } func FindNetworkInterfacesByAttachmentInstanceOwnerIDAndDescription(conn *ec2.EC2, attachmentInstanceOwnerID, description string) ([]*ec2.NetworkInterface, error) { + return FindNetworkInterfacesByAttachmentInstanceOwnerIDAndDescriptionWithContext(context.Background(), conn, attachmentInstanceOwnerID, description) +} + +func FindNetworkInterfacesByAttachmentInstanceOwnerIDAndDescriptionWithContext(ctx context.Context, conn *ec2.EC2, attachmentInstanceOwnerID, description string) ([]*ec2.NetworkInterface, error) { input := &ec2.DescribeNetworkInterfacesInput{ Filters: BuildAttributeFilterList(map[string]string{ "attachment.instance-owner-id": attachmentInstanceOwnerID, @@ -1411,17 +1419,17 @@ func FindNetworkInterfacesByAttachmentInstanceOwnerIDAndDescription(conn *ec2.EC }), } - return FindNetworkInterfaces(conn, input) + return FindNetworkInterfacesWithContext(ctx, conn, input) } -func FindNetworkInterfaceAttachmentByID(conn *ec2.EC2, id string) (*ec2.NetworkInterfaceAttachment, error) { +func FindNetworkInterfaceAttachmentByID(ctx context.Context, conn *ec2.EC2, id string) (*ec2.NetworkInterfaceAttachment, error) { input := &ec2.DescribeNetworkInterfacesInput{ Filters: BuildAttributeFilterList(map[string]string{ "attachment.attachment-id": id, }), } - networkInterface, err := FindNetworkInterface(conn, input) + networkInterface, err := FindNetworkInterfaceWithContext(ctx, conn, input) if err != nil { return nil, err diff --git a/internal/service/ec2/status.go b/internal/service/ec2/status.go index 43b87c56d1a..a21edad4d50 100644 --- a/internal/service/ec2/status.go +++ b/internal/service/ec2/status.go @@ -1,6 +1,7 @@ package ec2 import ( + "context" "fmt" "strconv" @@ -1125,9 +1126,9 @@ func StatusNetworkInterfaceStatus(conn *ec2.EC2, id string) resource.StateRefres } } -func StatusNetworkInterfaceAttachmentStatus(conn *ec2.EC2, id string) resource.StateRefreshFunc { +func StatusNetworkInterfaceAttachmentStatus(ctx context.Context, conn *ec2.EC2, id string) resource.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := FindNetworkInterfaceAttachmentByID(conn, id) + output, err := FindNetworkInterfaceAttachmentByID(ctx, conn, id) if tfresource.NotFound(err) { return nil, "", nil diff --git a/internal/service/ec2/vpc_network_interface.go b/internal/service/ec2/vpc_network_interface.go index 090cc23930f..f4fe9e06748 100644 --- a/internal/service/ec2/vpc_network_interface.go +++ b/internal/service/ec2/vpc_network_interface.go @@ -4,12 +4,14 @@ import ( "context" "fmt" "log" + "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -1106,7 +1108,7 @@ func attachNetworkInterface(conn *ec2.EC2, networkInterfaceID, instanceID string attachmentID := aws.StringValue(output.AttachmentId) - _, err = WaitNetworkInterfaceAttached(conn, attachmentID, timeout) + _, err = WaitNetworkInterfaceAttached(context.TODO(), conn, attachmentID, timeout) if err != nil { return attachmentID, fmt.Errorf("error waiting for EC2 Network Interface (%s/%s) attach: %w", networkInterfaceID, attachmentID, err) @@ -1116,8 +1118,12 @@ func attachNetworkInterface(conn *ec2.EC2, networkInterfaceID, instanceID string } func DeleteNetworkInterface(conn *ec2.EC2, networkInterfaceID string) error { + return DeleteNetworkInterfaceWithContext(context.Background(), conn, networkInterfaceID) +} + +func DeleteNetworkInterfaceWithContext(ctx context.Context, conn *ec2.EC2, networkInterfaceID string) error { log.Printf("[INFO] Deleting EC2 Network Interface: %s", networkInterfaceID) - _, err := conn.DeleteNetworkInterface(&ec2.DeleteNetworkInterfaceInput{ + _, err := conn.DeleteNetworkInterfaceWithContext(ctx, &ec2.DeleteNetworkInterfaceInput{ NetworkInterfaceId: aws.String(networkInterfaceID), }) @@ -1133,13 +1139,17 @@ func DeleteNetworkInterface(conn *ec2.EC2, networkInterfaceID string) error { } func DetachNetworkInterface(conn *ec2.EC2, networkInterfaceID, attachmentID string, timeout time.Duration) error { + return DetachNetworkInterfaceWithContext(context.Background(), conn, networkInterfaceID, attachmentID, timeout) +} + +func DetachNetworkInterfaceWithContext(ctx context.Context, conn *ec2.EC2, networkInterfaceID, attachmentID string, timeout time.Duration) error { input := &ec2.DetachNetworkInterfaceInput{ AttachmentId: aws.String(attachmentID), Force: aws.Bool(true), } log.Printf("[INFO] Detaching EC2 Network Interface: %s", input) - _, err := conn.DetachNetworkInterface(input) + _, err := conn.DetachNetworkInterfaceWithContext(ctx, input) if tfawserr.ErrCodeEquals(err, errCodeInvalidAttachmentIDNotFound) { return nil @@ -1149,7 +1159,7 @@ func DetachNetworkInterface(conn *ec2.EC2, networkInterfaceID, attachmentID stri return fmt.Errorf("detaching EC2 Network Interface (%s/%s): %w", networkInterfaceID, attachmentID, err) } - _, err = WaitNetworkInterfaceDetached(conn, attachmentID, timeout) + _, err = WaitNetworkInterfaceDetached(ctx, conn, attachmentID, timeout) if tfresource.NotFound(err) { return nil @@ -1505,3 +1515,120 @@ func flattenIPv6PrefixSpecifications(apiObjects []*ec2.Ipv6PrefixSpecification) return tfList } + +// Some AWS services creates ENIs behind the scenes and keeps these around for a while +// which can prevent security groups and subnets attached to such ENIs from being destroyed +func deleteLingeringENIs(ctx context.Context, conn *ec2.EC2, filterName, resourceId string, timeout time.Duration) error { + var g multierror.Group + + err := multierror.Append(nil, deleteLingeringLambdaENIs(ctx, &g, conn, filterName, resourceId, timeout)) + + err = multierror.Append(err, deleteLingeringComprehendENIs(ctx, &g, conn, filterName, resourceId, timeout)) + + return multierror.Append(err, g.Wait()).ErrorOrNil() +} + +func deleteLingeringLambdaENIs(ctx context.Context, g *multierror.Group, conn *ec2.EC2, filterName, resourceId string, timeout time.Duration) error { + // AWS Lambda service team confirms P99 deletion time of ~35 minutes. Buffer for safety. + if minimumTimeout := 45 * time.Minute; timeout < minimumTimeout { + timeout = minimumTimeout + } + + networkInterfaces, err := FindNetworkInterfacesWithContext(ctx, conn, &ec2.DescribeNetworkInterfacesInput{ + Filters: BuildAttributeFilterList(map[string]string{ + filterName: resourceId, + "description": "AWS Lambda VPC ENI*", + }), + }) + + if err != nil { + return fmt.Errorf("error listing EC2 Network Interfaces: %w", err) + } + + for _, v := range networkInterfaces { + v := v + g.Go(func() error { + networkInterfaceID := aws.StringValue(v.NetworkInterfaceId) + + if v.Attachment != nil && aws.StringValue(v.Attachment.InstanceOwnerId) == "amazon-aws" { + networkInterface, err := WaitNetworkInterfaceAvailableAfterUse(conn, networkInterfaceID, timeout) + + if tfresource.NotFound(err) { + return nil + } + + if err != nil { + return fmt.Errorf("waiting for Lambda ENI (%s) to become available for detachment: %w", networkInterfaceID, err) + } + + v = networkInterface + } + + if v.Attachment != nil { + err = DetachNetworkInterface(conn, networkInterfaceID, aws.StringValue(v.Attachment.AttachmentId), timeout) + + if err != nil { + return fmt.Errorf("detaching Lambda ENI (%s): %w", networkInterfaceID, err) + } + } + + err = DeleteNetworkInterface(conn, networkInterfaceID) + + if err != nil { + return fmt.Errorf("deleting Lambda ENI (%s): %w", networkInterfaceID, err) + } + + return nil + }) + } + + return nil +} + +func deleteLingeringComprehendENIs(ctx context.Context, g *multierror.Group, conn *ec2.EC2, filterName, resourceId string, timeout time.Duration) error { + // Deletion appears to take approximately 5 minutes + if minimumTimeout := 10 * time.Minute; timeout < minimumTimeout { + timeout = minimumTimeout + } + + enis, err := FindNetworkInterfacesWithContext(ctx, conn, &ec2.DescribeNetworkInterfacesInput{ + Filters: BuildAttributeFilterList(map[string]string{ + filterName: resourceId, + }), + }) + if err != nil { + return fmt.Errorf("error listing EC2 Network Interfaces: %w", err) + } + + networkInterfaces := make([]*ec2.NetworkInterface, 0, len(enis)) + for _, v := range enis { + if strings.HasSuffix(aws.StringValue(v.RequesterId), ":Comprehend") { + networkInterfaces = append(networkInterfaces, v) + } + } + + for _, v := range networkInterfaces { + v := v + g.Go(func() error { + networkInterfaceID := aws.StringValue(v.NetworkInterfaceId) + + if v.Attachment != nil { + err = DetachNetworkInterface(conn, networkInterfaceID, aws.StringValue(v.Attachment.AttachmentId), timeout) + + if err != nil { + return fmt.Errorf("detaching Comprehend ENI (%s): %w", networkInterfaceID, err) + } + } + + err := DeleteNetworkInterface(conn, networkInterfaceID) + + if err != nil { + return fmt.Errorf("deleting Comprehend ENI (%s): %w", networkInterfaceID, err) + } + + return nil + }) + } + + return nil +} diff --git a/internal/service/ec2/vpc_network_interface_attachment.go b/internal/service/ec2/vpc_network_interface_attachment.go index 05584f1375a..1c7c49bea13 100644 --- a/internal/service/ec2/vpc_network_interface_attachment.go +++ b/internal/service/ec2/vpc_network_interface_attachment.go @@ -1,6 +1,7 @@ package ec2 import ( + "context" "fmt" "log" @@ -68,7 +69,7 @@ func resourceNetworkInterfaceAttachmentCreate(d *schema.ResourceData, meta inter func resourceNetworkInterfaceAttachmentRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - attachment, err := FindNetworkInterfaceAttachmentByID(conn, d.Id()) + attachment, err := FindNetworkInterfaceAttachmentByID(context.TODO(), conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] EC2 Network Interface Attachment (%s) not found, removing from state", d.Id()) diff --git a/internal/service/ec2/vpc_network_interface_data_source.go b/internal/service/ec2/vpc_network_interface_data_source.go index 67065d8fcb7..60e806067b1 100644 --- a/internal/service/ec2/vpc_network_interface_data_source.go +++ b/internal/service/ec2/vpc_network_interface_data_source.go @@ -1,6 +1,7 @@ package ec2 import ( + "context" "fmt" "time" @@ -169,7 +170,7 @@ func dataSourceNetworkInterfaceRead(d *schema.ResourceData, meta interface{}) er input.NetworkInterfaceIds = []*string{aws.String(v.(string))} } - eni, err := FindNetworkInterface(conn, input) + eni, err := FindNetworkInterfaceWithContext(context.TODO(), conn, input) if err != nil { return fmt.Errorf("error reading EC2 Network Interface: %w", err) diff --git a/internal/service/ec2/vpc_network_interfaces_data_source.go b/internal/service/ec2/vpc_network_interfaces_data_source.go index 5b25cc006e4..57e0496afe7 100644 --- a/internal/service/ec2/vpc_network_interfaces_data_source.go +++ b/internal/service/ec2/vpc_network_interfaces_data_source.go @@ -1,6 +1,7 @@ package ec2 import ( + "context" "fmt" "time" @@ -50,7 +51,7 @@ func dataSourceNetworkInterfacesRead(d *schema.ResourceData, meta interface{}) e networkInterfaceIDs := []string{} - output, err := FindNetworkInterfaces(conn, input) + output, err := FindNetworkInterfacesWithContext(context.TODO(), conn, input) if err != nil { return fmt.Errorf("error reading EC2 Network Interfaces: %w", err) diff --git a/internal/service/ec2/vpc_security_group.go b/internal/service/ec2/vpc_security_group.go index 649c57e053c..17d634a44be 100644 --- a/internal/service/ec2/vpc_security_group.go +++ b/internal/service/ec2/vpc_security_group.go @@ -2,6 +2,7 @@ package ec2 import ( "bytes" + "context" "fmt" "log" "regexp" @@ -363,8 +364,8 @@ func resourceSecurityGroupUpdate(d *schema.ResourceData, meta interface{}) error func resourceSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn - if err := deleteLingeringLambdaENIs(conn, "group-id", d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("deleting Lambda ENIs using Security Group (%s): %w", d.Id(), err) + if err := deleteLingeringENIs(context.TODO(), conn, "group-id", d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return fmt.Errorf("deleting ENIs using Security Group (%s): %w", d.Id(), err) } // conditionally revoke rules first before attempting to delete the group @@ -1263,56 +1264,6 @@ var securityGroupProtocolIntegers = map[string]int{ "all": -1, } -// The AWS Lambda service creates ENIs behind the scenes and keeps these around for a while -// which would prevent SGs attached to such ENIs from being destroyed -func deleteLingeringLambdaENIs(conn *ec2.EC2, filterName, resourceID string, timeout time.Duration) error { - // AWS Lambda service team confirms P99 deletion time of ~35 minutes. Buffer for safety. - if minimumTimeout := 45 * time.Minute; timeout < minimumTimeout { - timeout = minimumTimeout - } - - networkInterfaces, err := FindNetworkInterfaces(conn, &ec2.DescribeNetworkInterfacesInput{ - Filters: BuildAttributeFilterList(map[string]string{ - filterName: resourceID, - "description": "AWS Lambda VPC ENI*", - }), - }) - - if err != nil { - return fmt.Errorf("listing EC2 Network Interfaces: %w", err) - } - - for _, v := range networkInterfaces { - networkInterfaceID := aws.StringValue(v.NetworkInterfaceId) - - if v.Attachment != nil && aws.StringValue(v.Attachment.InstanceOwnerId) == "amazon-aws" { - networkInterface, err := WaitNetworkInterfaceAvailableAfterUse(conn, networkInterfaceID, timeout) - - if tfresource.NotFound(err) { - continue - } - - if err != nil { - return fmt.Errorf("waiting for Lambda ENI (%s) to become available after use: %w", networkInterfaceID, err) - } - - v = networkInterface - } - - if v.Attachment != nil { - if err := DetachNetworkInterface(conn, networkInterfaceID, aws.StringValue(v.Attachment.AttachmentId), timeout); err != nil { - return err - } - } - - if err := DeleteNetworkInterface(conn, networkInterfaceID); err != nil { - return err - } - } - - return nil -} - func initSecurityGroupRule(ruleMap map[string]map[string]interface{}, perm *ec2.IpPermission, desc string) map[string]interface{} { var fromPort, toPort int64 if v := perm.FromPort; v != nil { diff --git a/internal/service/ec2/vpc_subnet.go b/internal/service/ec2/vpc_subnet.go index 973648a0ec5..584b43d1f23 100644 --- a/internal/service/ec2/vpc_subnet.go +++ b/internal/service/ec2/vpc_subnet.go @@ -1,6 +1,7 @@ package ec2 import ( + "context" "fmt" "log" "time" @@ -361,8 +362,8 @@ func resourceSubnetDelete(d *schema.ResourceData, meta interface{}) error { log.Printf("[INFO] Deleting EC2 Subnet: %s", d.Id()) - if err := deleteLingeringLambdaENIs(conn, "subnet-id", d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return fmt.Errorf("error deleting Lambda ENIs using EC2 Subnet (%s): %w", d.Id(), err) + if err := deleteLingeringENIs(context.TODO(), conn, "subnet-id", d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + return fmt.Errorf("deleting ENIs for EC2 Subnet (%s): %w", d.Id(), err) } _, err := tfresource.RetryWhenAWSErrCodeEquals(d.Timeout(schema.TimeoutDelete), func() (interface{}, error) { @@ -376,7 +377,7 @@ func resourceSubnetDelete(d *schema.ResourceData, meta interface{}) error { } if err != nil { - return fmt.Errorf("error deleting EC2 Subnet (%s): %w", d.Id(), err) + return fmt.Errorf("deleting EC2 Subnet (%s): %w", d.Id(), err) } return nil diff --git a/internal/service/ec2/wait.go b/internal/service/ec2/wait.go index ab023150070..7148cacc6d3 100644 --- a/internal/service/ec2/wait.go +++ b/internal/service/ec2/wait.go @@ -1,6 +1,7 @@ package ec2 import ( + "context" "errors" "fmt" "strconv" @@ -2274,15 +2275,15 @@ const ( NetworkInterfaceDetachedTimeout = 10 * time.Minute ) -func WaitNetworkInterfaceAttached(conn *ec2.EC2, id string, timeout time.Duration) (*ec2.NetworkInterfaceAttachment, error) { +func WaitNetworkInterfaceAttached(ctx context.Context, conn *ec2.EC2, id string, timeout time.Duration) (*ec2.NetworkInterfaceAttachment, error) { stateConf := &resource.StateChangeConf{ Pending: []string{ec2.AttachmentStatusAttaching}, Target: []string{ec2.AttachmentStatusAttached}, Timeout: timeout, - Refresh: StatusNetworkInterfaceAttachmentStatus(conn, id), + Refresh: StatusNetworkInterfaceAttachmentStatus(ctx, conn, id), } - outputRaw, err := stateConf.WaitForState() + outputRaw, err := stateConf.WaitForStateContext(ctx) if output, ok := outputRaw.(*ec2.NetworkInterfaceAttachment); ok { return output, err @@ -2332,15 +2333,15 @@ func WaitNetworkInterfaceCreated(conn *ec2.EC2, id string, timeout time.Duration return nil, err } -func WaitNetworkInterfaceDetached(conn *ec2.EC2, id string, timeout time.Duration) (*ec2.NetworkInterfaceAttachment, error) { +func WaitNetworkInterfaceDetached(ctx context.Context, conn *ec2.EC2, id string, timeout time.Duration) (*ec2.NetworkInterfaceAttachment, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{ec2.AttachmentStatusDetaching}, + Pending: []string{ec2.AttachmentStatusAttached, ec2.AttachmentStatusDetaching}, Target: []string{ec2.AttachmentStatusDetached}, Timeout: timeout, - Refresh: StatusNetworkInterfaceAttachmentStatus(conn, id), + Refresh: StatusNetworkInterfaceAttachmentStatus(ctx, conn, id), } - outputRaw, err := stateConf.WaitForState() + outputRaw, err := stateConf.WaitForStateContext(ctx) if output, ok := outputRaw.(*ec2.NetworkInterfaceAttachment); ok { return output, err diff --git a/names/names.go b/names/names.go index 061a5d9862c..da36d69acaf 100644 --- a/names/names.go +++ b/names/names.go @@ -23,6 +23,7 @@ import ( // This "should" be defined by the AWS Go SDK v2, but currently isn't. const ( + ComprehendEndpointID = "comprehend" KendraEndpointID = "kendra" RolesAnywhereEndpointID = "rolesanywhere" Route53DomainsEndpointID = "route53domains" diff --git a/names/names_data.csv b/names/names_data.csv index 8e1b98c378d..184e107caba 100644 --- a/names/names_data.csv +++ b/names/names_data.csv @@ -80,7 +80,7 @@ codestar-notifications,codestarnotifications,codestarnotifications,codestarnotif cognito-identity,cognitoidentity,cognitoidentity,cognitoidentity,,cognitoidentity,,,CognitoIdentity,CognitoIdentity,,1,aws_cognito_identity_(?!provider),aws_cognitoidentity_,,cognito_identity_pool,Cognito Identity,Amazon,,,,, cognito-idp,cognitoidp,cognitoidentityprovider,cognitoidentityprovider,,cognitoidp,,cognitoidentityprovider,CognitoIDP,CognitoIdentityProvider,,1,aws_cognito_(identity_provider|resource|user|risk),aws_cognitoidp_,,cognito_identity_provider;cognito_resource_;cognito_user;cognito_risk,Cognito IDP (Identity Provider),Amazon,,,,, cognito-sync,cognitosync,cognitosync,cognitosync,,cognitosync,,,CognitoSync,CognitoSync,,1,,aws_cognitosync_,,cognitosync_,Cognito Sync,Amazon,,,,, -comprehend,comprehend,comprehend,comprehend,,comprehend,,,Comprehend,Comprehend,,1,,aws_comprehend_,,comprehend_,Comprehend,Amazon,,,,, +comprehend,comprehend,comprehend,comprehend,,comprehend,,,Comprehend,Comprehend,x,2,,aws_comprehend_,,comprehend_,Comprehend,Amazon,,,,, comprehendmedical,comprehendmedical,comprehendmedical,comprehendmedical,,comprehendmedical,,,ComprehendMedical,ComprehendMedical,,1,,aws_comprehendmedical_,,comprehendmedical_,Comprehend Medical,Amazon,,,,, compute-optimizer,computeoptimizer,computeoptimizer,computeoptimizer,,computeoptimizer,,,ComputeOptimizer,ComputeOptimizer,,1,,aws_computeoptimizer_,,computeoptimizer_,Compute Optimizer,AWS,,,,, configservice,configservice,configservice,configservice,,configservice,,config,ConfigService,ConfigService,,1,aws_config_,aws_configservice_,,config_,Config,AWS,,,,, diff --git a/skaff/README.md b/skaff/README.md index aed34190f64..5d7c1d02f35 100644 --- a/skaff/README.md +++ b/skaff/README.md @@ -2,4 +2,4 @@ `skaff` is a Terraform AWS Provider scaffolding command line tool. It generates resource/data source files and accompanying test files which adhere to the latest best practice. These files are heavily commented with instructions so serve as the best way to get started with provider development. -See the [Provider Scaffolding Documentation](https://hashicorp.github.io/terraform-provider-aws/skaff/) for details on how to use `skaff`. \ No newline at end of file +See the [Provider Scaffolding Documentation](https://hashicorp.github.io/terraform-provider-aws/skaff/) for details on how to use `skaff`. diff --git a/website/docs/r/comprehend_entity_recognizer.html.markdown b/website/docs/r/comprehend_entity_recognizer.html.markdown new file mode 100644 index 00000000000..a2c9b8ba1cd --- /dev/null +++ b/website/docs/r/comprehend_entity_recognizer.html.markdown @@ -0,0 +1,165 @@ +--- +subcategory: "Comprehend" +layout: "aws" +page_title: "AWS: aws_comprehend_entity_recognizer" +description: |- + Terraform resource for managing an AWS Comprehend Entity Recognizer. +--- + +# Resource: aws_comprehend_entity_recognizer + +Terraform resource for managing an AWS Comprehend EntityRecognizer. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_comprehend_entity_recognizer" "example" { + name = "example" + + data_access_role_arn = aws_iam_role.example.arn + + language_code = "en" + input_data_config { + entity_types { + type = "ENTITY_1" + } + entity_types { + type = "ENTITY_2" + } + + documents { + s3_uri = "s3://${aws_s3_bucket.documents.bucket}/${aws_s3_object.documents.id}" + } + + entity_list { + s3_uri = "s3://${aws_s3_bucket.entities.bucket}/${aws_s3_object.entities.id}" + } + } + + depends_on = [ + aws_iam_role_policy.example + ] +} + +resource "aws_s3_object" "documents" { + # ... +} + +resource "aws_s3_object" "entities" { + # ... +} +``` + +## Argument Reference + +The following arguments are required: + +* `data_access_role_arn` - (Required) The ARN for an IAM Role which allows Comprehend to read the training and testing data. +* `input_data_config` - (Required) Configuration for the training and testing data. + See the [`input_data_config` Configuration Block](#input_data_config-configuration-block) section below. +* `language_code` - (Required) Two-letter language code for the language. + One of `en`, `es`, `fr`, `it`, `de`, or `pt`. +* `name` - (Required) Name for the Entity Recognizer. + Has a maximum length of 63 characters. + Can contain upper- and lower-case letters, numbers, and hypen (`-`). + +The following arguments are optional: + +* `model_kms_key_id` - (Optional) The ID or ARN of a KMS Key used to encrypt trained Entity Recognizers. +* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` Configuration Block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +* `version_name` - (Optional) Name for the version of the Entity Recognizer. + Each version must have a unique name within the Entity Recognizer. + If omitted, Terraform will assign a random, unique version name. + If explicitly set to `""`, no version name will be set. + Has a maximum length of 63 characters. + Can contain upper- and lower-case letters, numbers, and hypen (`-`). + Conflicts with `version_name_prefix`. +* `version_name_prefix` - (Optional) Creates a unique version name beginning with the specified prefix. + Has a maximum length of 37 characters. + Can contain upper- and lower-case letters, numbers, and hypen (`-`). + Conflicts with `version_name`. +* `volume_kms_key_id` - (Optional) ID or ARN of a KMS Key used to encrypt storage volumes during job processing. +* `vpc_config` - (Optional) Configuration parameters for VPC to contain Entity Recognizer resources. + See the [`vpc_config` Configuration Block](#vpc_config-configuration-block) section below. + +### `input_data_config` Configuration Block + +* `annotations` - (Optional) Specifies location of the document annotation data. + See the [`annotations` Configuration Block](#annotations-configuration-block) section below. + One of `annotations` or `entity_list` is required. +* `augmented_manifests` - (Optional) List of training datasets produced by Amazon SageMaker Ground Truth. + Used if `data_format` is `AUGMENTED_MANIFEST`. + See the [`augmented_manifests` Configuration Block](#augmented_manifests-configuration-block) section below. +* `data_format` - (Optional, Default: `COMPREHEND_CSV`) The format for the training data. + One of `COMPREHEND_CSV` or `AUGMENTED_MANIFEST`. +* `documents` - (Optional) Specifies a collection of training documents. + Used if `data_format` is `COMPREHEND_CSV`. + See the [`documents` Configuration Block](#documents-configuration-block) section below. +* `entity_list` - (Optional) Specifies location of the entity list data. + See the [`entity_list` Configuration Block](#entity_list-configuration-block) section below. + One of `entity_list` or `annotations` is required. +* `entity_types` - (Required) Set of entity types to be recognized. + Has a maximum of 25 items. + See the [`entity_types` Configuration Block](#entity_types-configuration-block) section below. + +### `annotations` Configuration Block + +* `s3_uri` - (Required) Location of training annotations. +* `test_s3uri` - (Optional) Location of test annotations. + +### `augmented_manifests` Configuration Block + +* `annotation_data_s3_uri` - (Optional) Location of annotation files. +* `attribute_names` - (Required) The JSON attribute that contains the annotations for the training documents. +* `document_type` - (Optional, Default: `PLAIN_TEXT_DOCUMENT`) Type of augmented manifest. + One of `PLAIN_TEXT_DOCUMENT` or `SEMI_STRUCTURED_DOCUMENT`. +* `s3_uri` - (Required) Location of augmented manifest file. +* `source_documents_s3_uri` - (Optional) Location of source PDF files. +* `split` - (Optional, Default: `TRAIN`) Purpose of data in augmented manifest. + One of `TRAIN` or `TEST`. + +### `documents` Configuration Block + +* `input_format` - (Optional, Default: `ONE_DOC_PER_LINE`) Specifies how the input files should be processed. + One of `ONE_DOC_PER_LINE` or `ONE_DOC_PER_FILE`. +* `s3_uri` - (Required) Location of training documents. +* `test_s3uri` - (Optional) Location of test documents. + +### `entity_list` Configuration Block + +* `s3_uri` - (Required) Location of entity list. + +### `entity_types` Configuration Block + +* `type` - (Required) An entity type to be matched by the Entity Recognizer. + Cannot contain a newline (`\n`), carriage return (`\r`), or tab (`\t`). + +### `vpc_config` Configuration Block + +* `security_group_ids` - (Required) List of security group IDs. +* `subnets` - (Required) List of VPC subnets. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the Entity Recognizer version. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block). + +## Timeouts + +`aws_comprehend_entity_recognizer` provides the following [Timeouts](https://www.terraform.io/docs/configuration/blocks/resources/syntax.html#operation-timeouts) configuration options: + +* `create` - (Optional, Default: `20m`) +* `update` - (Optional, Default: `20m`) +* `delete` - (Optional, Default: `20m`) + +## Import + +Comprehend Entity Recognizer can be imported using the ARN, e.g., + +``` +$ terraform import aws_comprehend_entity_recognizer.example arn:aws:comprehend:us-west-2:123456789012:entity-recognizer/example +```