From 82ad12de4be6c686cdd09000b888574d88e8b249 Mon Sep 17 00:00:00 2001 From: Bhavya Agrawal Date: Wed, 31 May 2023 21:00:57 +0530 Subject: [PATCH] feat: [PL-38510]: added resource for api tokens (#556) * [PL-38510]: added resource for api tokens --- .changelog/556.txt | 3 + docs/data-sources/platform_token.md | 56 +++ docs/resources/platform_token.md | 93 +++++ .../harness_platform_token/data-source.tf | 8 + .../harness_platform_token/import.sh | 8 + .../harness_platform_token/resource.tf | 32 ++ go.mod | 21 +- go.sum | 70 ++-- internal/provider/provider.go | 3 + .../platform/token/data_source_token.go | 155 ++++++++ .../platform/token/data_source_token_test.go | 214 +++++++++++ .../service/platform/token/resource_token.go | 336 ++++++++++++++++++ .../platform/token/resource_token_test.go | 305 ++++++++++++++++ 13 files changed, 1274 insertions(+), 30 deletions(-) create mode 100644 .changelog/556.txt create mode 100644 docs/data-sources/platform_token.md create mode 100644 docs/resources/platform_token.md create mode 100644 examples/data-sources/harness_platform_token/data-source.tf create mode 100644 examples/resources/harness_platform_token/import.sh create mode 100644 examples/resources/harness_platform_token/resource.tf create mode 100644 internal/service/platform/token/data_source_token.go create mode 100644 internal/service/platform/token/data_source_token_test.go create mode 100644 internal/service/platform/token/resource_token.go create mode 100644 internal/service/platform/token/resource_token_test.go diff --git a/.changelog/556.txt b/.changelog/556.txt new file mode 100644 index 000000000..ad62b1488 --- /dev/null +++ b/.changelog/556.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +platform_token - Added apikey token in Harness terraform provider +``` \ No newline at end of file diff --git a/docs/data-sources/platform_token.md b/docs/data-sources/platform_token.md new file mode 100644 index 000000000..2cc60456e --- /dev/null +++ b/docs/data-sources/platform_token.md @@ -0,0 +1,56 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harness_platform_token Data Source - terraform-provider-harness" +subcategory: "Next Gen" +description: |- + Data source for retrieving a Harness ApiKey Token. +--- + +# harness_platform_token (Data Source) + +Data source for retrieving a Harness ApiKey Token. + +## Example Usage + +```terraform +data "harness_platform_token" "test" { + identifier = "test_token" + parent_id = "apikey_parent_id" + org_id = "org_id" + project_id = "project_id" + apikey_id = "apikey_id" + apikey_type = "USER" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account Identifier for the Entity +- `apikey_id` (String) Identifier of the API Key +- `apikey_type` (String) Type of the API Key +- `identifier` (String) Identifier of the Token +- `name` (String) Name of the Token +- `parent_id` (String) Parent Entity Identifier of the API Key + +### Optional + +- `description` (String) Description of the Token +- `email` (String) Email Id of the user who created the Token +- `encoded_password` (String) Encoded password of the Token +- `org_id` (String) Organization Identifier for the Entity +- `project_id` (String) Project Identifier for the Entity +- `scheduled_expire_time` (Number) Scheduled expiry time in milliseconds +- `tags` (Map of String) Tags for the Token +- `username` (String) Name of the user who created the Token +- `valid` (Boolean) Boolean value to indicate if Token is valid or not. +- `valid_from` (Number) This is the time from which the Token is valid. The time is in milliseconds +- `valid_to` (Number) This is the time till which the Token is valid. The time is in milliseconds + +### Read-Only + +- `id` (String) The ID of this resource. + + diff --git a/docs/resources/platform_token.md b/docs/resources/platform_token.md new file mode 100644 index 000000000..33599fe54 --- /dev/null +++ b/docs/resources/platform_token.md @@ -0,0 +1,93 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harness_platform_token Resource - terraform-provider-harness" +subcategory: "Next Gen" +description: |- + Resource for creating tokens. +--- + +# harness_platform_token (Resource) + +Resource for creating tokens. + +## Example Usage + +```terraform +# Create token for account level apikey +resource "harness_platform_token" "test" { + identifier = "test_token" + name = "test token" + parent_id = "apikey_parent_id" + account_id = "account_id" + apikey_type = "USER" + apikey_id = "apikey_id" +} + +# Create token for org level apikey +resource "harness_platform_token" "test" { + identifier = "test_token" + name = "test token" + parent_id = "apikey_parent_id" + account_id = "account_id" + org_id = "org_id" + apikey_type = "USER" + apikey_id = "apikey_id" +} + +# Create token for project level apikey +resource "harness_platform_token" "test" { + identifier = "test_token" + name = "test token" + parent_id = "apikey_parent_id" + account_id = "account_id" + org_id = "org_id" + project_id = "project_id" + apikey_type = "USER" + apikey_id = "apikey_id" +} +``` + + +## Schema + +### Required + +- `account_id` (String) Account Identifier for the Entity +- `apikey_id` (String) Identifier of the API Key +- `apikey_type` (String) Type of the API Key +- `identifier` (String) Identifier of the Token +- `name` (String) Name of the Token +- `parent_id` (String) Parent Entity Identifier of the API Key + +### Optional + +- `description` (String) Description of the Token +- `email` (String) Email Id of the user who created the Token +- `encoded_password` (String) Encoded password of the Token +- `org_id` (String) Organization Identifier for the Entity +- `project_id` (String) Project Identifier for the Entity +- `scheduled_expire_time` (Number) Scheduled expiry time in milliseconds +- `tags` (Map of String) Tags for the Token +- `username` (String) Name of the user who created the Token +- `valid` (Boolean) Boolean value to indicate if Token is valid or not. +- `valid_from` (Number) This is the time from which the Token is valid. The time is in milliseconds +- `valid_to` (Number) This is the time till which the Token is valid. The time is in milliseconds + +### Read-Only + +- `id` (String) The ID of this resource. + +## Import + +Import is supported using the following syntax: + +```shell +# Import account level token +terraform import harness_platform_token /// + +# Import org level token +terraform import harness_platform_token //// + +# Import project level token +terraform import harness_platform_token ///// +``` diff --git a/examples/data-sources/harness_platform_token/data-source.tf b/examples/data-sources/harness_platform_token/data-source.tf new file mode 100644 index 000000000..169456a79 --- /dev/null +++ b/examples/data-sources/harness_platform_token/data-source.tf @@ -0,0 +1,8 @@ +data "harness_platform_token" "test" { + identifier = "test_token" + parent_id = "apikey_parent_id" + org_id = "org_id" + project_id = "project_id" + apikey_id = "apikey_id" + apikey_type = "USER" +} \ No newline at end of file diff --git a/examples/resources/harness_platform_token/import.sh b/examples/resources/harness_platform_token/import.sh new file mode 100644 index 000000000..cda639581 --- /dev/null +++ b/examples/resources/harness_platform_token/import.sh @@ -0,0 +1,8 @@ +# Import account level token +terraform import harness_platform_token /// + +# Import org level token +terraform import harness_platform_token //// + +# Import project level token +terraform import harness_platform_token ///// \ No newline at end of file diff --git a/examples/resources/harness_platform_token/resource.tf b/examples/resources/harness_platform_token/resource.tf new file mode 100644 index 000000000..26a305359 --- /dev/null +++ b/examples/resources/harness_platform_token/resource.tf @@ -0,0 +1,32 @@ +# Create token for account level apikey +resource "harness_platform_token" "test" { + identifier = "test_token" + name = "test token" + parent_id = "apikey_parent_id" + account_id = "account_id" + apikey_type = "USER" + apikey_id = "apikey_id" +} + +# Create token for org level apikey +resource "harness_platform_token" "test" { + identifier = "test_token" + name = "test token" + parent_id = "apikey_parent_id" + account_id = "account_id" + org_id = "org_id" + apikey_type = "USER" + apikey_id = "apikey_id" +} + +# Create token for project level apikey +resource "harness_platform_token" "test" { + identifier = "test_token" + name = "test token" + parent_id = "apikey_parent_id" + account_id = "account_id" + org_id = "org_id" + project_id = "project_id" + apikey_type = "USER" + apikey_id = "apikey_id" +} \ No newline at end of file diff --git a/go.mod b/go.mod index c709c6427..361e93cd9 100644 --- a/go.mod +++ b/go.mod @@ -15,14 +15,16 @@ require ( require ( github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-retryablehttp v0.7.2 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.2 ) require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/go-connections v0.4.0 // indirect @@ -39,7 +41,7 @@ require ( github.com/hashicorp/go-plugin v1.4.9 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-version v1.6.0 // indirect - github.com/hashicorp/hc-install v0.5.1 // indirect + github.com/hashicorp/hc-install v0.5.2 // indirect github.com/hashicorp/hcl/v2 v2.16.2 // indirect github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.18.1 // indirect @@ -51,9 +53,9 @@ require ( github.com/hashicorp/yamux v0.1.1 // indirect github.com/jhump/protoreflect v1.6.1 // indirect github.com/jinzhu/copier v0.3.5 // indirect - github.com/kr/pretty v0.3.0 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect @@ -63,21 +65,20 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/t-tomalak/logrus-easy-formatter v0.0.0-20190827215021-c074f06c5816 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/zclconf/go-cty v1.13.1 // indirect - golang.org/x/crypto v0.8.0 // indirect + github.com/zclconf/go-cty v1.13.2 // indirect + golang.org/x/crypto v0.9.0 // indirect golang.org/x/mod v0.10.0 // indirect - golang.org/x/net v0.9.0 // indirect - golang.org/x/oauth2 v0.7.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/oauth2 v0.8.0 // indirect golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/tools v0.6.0 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect + google.golang.org/genproto v0.0.0-20230524185152-1884fd1fac28 // indirect google.golang.org/grpc v1.55.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 5c1319db8..cac8c26f4 100644 --- a/go.sum +++ b/go.sum @@ -2,7 +2,8 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= -github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= +github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek= +github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= @@ -11,7 +12,10 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= -github.com/cloudflare/circl v1.1.0 h1:bZgT/A+cikZnKIwn7xL2OBj012Bmvho/o6RpRvv3GKY= +github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -71,6 +75,8 @@ github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/C github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/hc-install v0.5.2 h1:SfwMFnEXVVirpwkDuSF5kymUOhrUxrTq3udEseZdOD0= +github.com/hashicorp/hc-install v0.5.2/go.mod h1:9QISwe6newMWIfEiXpzuu1k9HAGtQYgnSH8H9T8wmoI= github.com/hashicorp/hc-install v0.5.1 h1:eCqToNCob7m2R8kM8Gr7XcVmcRSz9ppCFSVZbMh0X+0= github.com/hashicorp/hc-install v0.5.1/go.mod h1:iDPCnzKo+SzToOh25R8OWpLdhhy7yBfJX3PmVWiYhrM= github.com/hashicorp/hcl/v2 v2.16.2 h1:mpkHZh/Tv+xet3sy3F9Ld4FyI2tUpWe9x3XtPx9f1a0= @@ -104,8 +110,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -118,8 +124,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= -github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= @@ -140,17 +146,17 @@ github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3I github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.1.0 h1:Wvr9V0MxhjRbl3f9nMnKnFfiWTJmtECJ9Njkea3ysW0= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -177,15 +183,20 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/zclconf/go-cty v1.13.1 h1:0a6bRwuiSHtAmqCqNOE+c2oHgepv0ctoxU4FUe43kwc= -github.com/zclconf/go-cty v1.13.1/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zclconf/go-cty v1.13.2 h1:4GvrUxe/QUDYuJKAav4EYqdM47/kZa672LwmXFmEKT0= +github.com/zclconf/go-cty v1.13.2/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -193,34 +204,53 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g= -golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8= +golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= @@ -230,6 +260,7 @@ golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -240,8 +271,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= +google.golang.org/genproto v0.0.0-20230524185152-1884fd1fac28 h1:+55/MuGJORMxCrkAgo2595fMAnN/4rweCuwibbqrvpc= +google.golang.org/genproto v0.0.0-20230524185152-1884fd1fac28/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= @@ -252,7 +283,6 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/provider/provider.go b/internal/provider/provider.go index f3df796f4..d35fc01a0 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -65,6 +65,7 @@ import ( "github.com/harness/terraform-provider-harness/internal/service/platform/slo" pl_template "github.com/harness/terraform-provider-harness/internal/service/platform/template" "github.com/harness/terraform-provider-harness/internal/service/platform/template_filters" + pl_token "github.com/harness/terraform-provider-harness/internal/service/platform/token" "github.com/harness/terraform-provider-harness/internal/service/platform/triggers" pl_user "github.com/harness/terraform-provider-harness/internal/service/platform/user" "github.com/harness/terraform-provider-harness/internal/service/platform/usergroup" @@ -217,6 +218,7 @@ func Provider(version string) func() *schema.Provider { "harness_platform_manual_freeze": manual_freeze.DataSourceManualFreeze(), "harness_platform_connector_service_now": connector.DataSourceConnectorSerivceNow(), "harness_platform_apikey": pl_apikey.DataSourceApiKey(), + "harness_platform_token": pl_token.DataSourceToken(), }, ResourcesMap: map[string]*schema.Resource{ "harness_platform_template": pl_template.ResourceTemplate(), @@ -326,6 +328,7 @@ func Provider(version string) func() *schema.Provider { "harness_platform_manual_freeze": manual_freeze.ResourceManualFreeze(), "harness_platform_connector_service_now": connector.ResourceConnectorServiceNow(), "harness_platform_apikey": pl_apikey.ResourceApiKey(), + "harness_platform_token": pl_token.ResourceToken(), }, } diff --git a/internal/service/platform/token/data_source_token.go b/internal/service/platform/token/data_source_token.go new file mode 100644 index 000000000..7cdb72362 --- /dev/null +++ b/internal/service/platform/token/data_source_token.go @@ -0,0 +1,155 @@ +package token + +import ( + "context" + "errors" + "net/http" + + "github.com/antihax/optional" + "github.com/harness/harness-go-sdk/harness/nextgen" + "github.com/harness/terraform-provider-harness/helpers" + "github.com/harness/terraform-provider-harness/internal" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func DataSourceToken() *schema.Resource { + resource := &schema.Resource{ + Description: "Data source for retrieving a Harness ApiKey Token.", + + ReadContext: dataSourceTokenRead, + + Schema: map[string]*schema.Schema{ + "identifier": { + Description: "Identifier of the Token", + Type: schema.TypeString, + Required: true, + }, + "name": { + Description: "Name of the Token", + Type: schema.TypeString, + Required: true, + }, + "apikey_id": { + Description: "Identifier of the API Key", + Type: schema.TypeString, + Required: true, + }, + "apikey_type": { + Description: "Type of the API Key", + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"USER", "SERVICE_ACCOUNT"}, false), + }, + "parent_id": { + Description: "Parent Entity Identifier of the API Key", + Type: schema.TypeString, + Required: true, + }, + "account_id": { + Description: "Account Identifier for the Entity", + Type: schema.TypeString, + Required: true, + }, + "org_id": { + Description: "Organization Identifier for the Entity", + Type: schema.TypeString, + Optional: true, + }, + "project_id": { + Description: "Project Identifier for the Entity", + Type: schema.TypeString, + Optional: true, + }, + "valid_from": { + Description: "This is the time from which the Token is valid. The time is in milliseconds", + Type: schema.TypeInt, + Optional: true, + }, + "valid_to": { + Description: "This is the time till which the Token is valid. The time is in milliseconds", + Type: schema.TypeInt, + Optional: true, + }, + "scheduled_expire_time": { + Description: "Scheduled expiry time in milliseconds", + Type: schema.TypeInt, + Optional: true, + }, + "valid": { + Description: "Boolean value to indicate if Token is valid or not.", + Type: schema.TypeBool, + Optional: true, + }, + "description": { + Description: "Description of the Token", + Type: schema.TypeString, + Optional: true, + }, + "email": { + Description: "Email Id of the user who created the Token", + Type: schema.TypeString, + Optional: true, + }, + "username": { + Description: "Name of the user who created the Token", + Type: schema.TypeString, + Optional: true, + }, + "encoded_password": { + Description: "Encoded password of the Token", + Type: schema.TypeString, + Optional: true, + }, + "tags": { + Description: "Tags for the Token", + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } + + return resource +} + +func dataSourceTokenRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + + var token *nextgen.Token + + id := d.Get("identifier").(string) + apikey_type := d.Get("apikey_type").(string) + parentId := d.Get("parent_id").(string) + apikey_id := d.Get("apikey_id").(string) + + if id != "" { + var err error + var httpResp *http.Response + resp, httpResp, err := c.TokenApi.ListAggregatedTokens(ctx, c.AccountId, apikey_type, parentId, apikey_id, &nextgen.TokenApiListAggregatedTokensOpts{ + OrgIdentifier: helpers.BuildField(d, "org_id"), + ProjectIdentifier: helpers.BuildField(d, "project_id"), + Identifiers: optional.NewInterface(id), + }) + tokenList := resp.Data.Content + if err != nil { + return helpers.HandleApiError(err, d, httpResp) + } + + if tokenList == nil || len(tokenList) == 0 { + d.SetId("") + d.MarkNewResource() + return nil + } else { + token = tokenList[0].Token + } + + } else { + return diag.FromErr(errors.New("Identifier must be specified")) + } + + readToken(d, token) + + return nil +} diff --git a/internal/service/platform/token/data_source_token_test.go b/internal/service/platform/token/data_source_token_test.go new file mode 100644 index 000000000..6f2a4d990 --- /dev/null +++ b/internal/service/platform/token/data_source_token_test.go @@ -0,0 +1,214 @@ +package token_test + +import ( + "fmt" + "os" + "testing" + + "github.com/harness/harness-go-sdk/harness/utils" + "github.com/harness/terraform-provider-harness/internal/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceToken(t *testing.T) { + + id := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + account_id := os.Getenv("HARNESS_ACCOUNT_ID") + parent_id := os.Getenv("HARNESS_PAT_KEY_PARENT_IDENTIFIER") + + tokenName := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + + resourceName := "data.harness_platform_token.test" + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceToken(id, tokenName, parent_id, account_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", id), + resource.TestCheckResourceAttr(resourceName, "name", tokenName), + ), + }, + }, + }) + +} + +func TestAccDataSourceTokenOrgLevel(t *testing.T) { + + id := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + account_id := os.Getenv("HARNESS_ACCOUNT_ID") + parent_id := os.Getenv("HARNESS_PAT_KEY_PARENT_IDENTIFIER") + + tokenName := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + + resourceName := "data.harness_platform_token.test" + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceTokenOrgLevel(id, tokenName, parent_id, account_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", id), + resource.TestCheckResourceAttr(resourceName, "name", tokenName), + resource.TestCheckResourceAttr(resourceName, "org_id", id), + ), + }, + }, + }) + +} + +func TestAccDataSourceTokenProjectLevel(t *testing.T) { + + id := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + account_id := os.Getenv("HARNESS_ACCOUNT_ID") + parent_id := os.Getenv("HARNESS_PAT_KEY_PARENT_IDENTIFIER") + + tokenName := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + + resourceName := "data.harness_platform_token.test" + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceTokenProjectLevel(id, tokenName, parent_id, account_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", id), + resource.TestCheckResourceAttr(resourceName, "name", tokenName), + resource.TestCheckResourceAttr(resourceName, "org_id", id), + resource.TestCheckResourceAttr(resourceName, "project_id", id), + ), + }, + }, + }) + +} + +func testAccDataSourceToken(id string, name string, parentId string, accountId string) string { + return fmt.Sprintf(` + resource "harness_platform_apikey" "test" { + identifier = "%[1]s" + name = "%[2]s" + parent_id = "%[3]s" + account_id = "%[4]s" + apikey_type = "USER" + default_time_to_expire_token = 1000000 + } + + resource "harness_platform_token" "test" { + identifier = "%[1]s" + name = "%[2]s" + description="Test Description" + parent_id = "%[3]s" + account_id = "%[4]s" + apikey_type = "USER" + apikey_id = harness_platform_apikey.test.id + } + + data "harness_platform_token" "test" { + identifier = harness_platform_token.test.identifier + parent_id = harness_platform_token.test.parent_id + apikey_type = harness_platform_token.test.apikey_type + account_id = harness_platform_token.test.account_id + name = harness_platform_token.test.name + apikey_id = harness_platform_token.test.apikey_id + } + `, id, name, parentId, accountId) +} + +func testAccDataSourceTokenOrgLevel(id string, name string, parentId string, accountId string) string { + return fmt.Sprintf(` + resource "harness_platform_organization" "test" { + identifier = "%[1]s" + name = "%[2]s" + } + + resource "harness_platform_apikey" "test" { + identifier = "%[1]s" + name = "%[2]s" + parent_id = "%[3]s" + account_id = "%[4]s" + org_id = harness_platform_organization.test.id + apikey_type = "USER" + default_time_to_expire_token = 1000000 + } + + resource "harness_platform_token" "test" { + identifier = "%[1]s" + name = "%[2]s" + description="Test Description" + parent_id = "%[3]s" + account_id = "%[4]s" + org_id = harness_platform_organization.test.id + apikey_type = "USER" + apikey_id = harness_platform_apikey.test.id + } + + data "harness_platform_token" "test" { + identifier = harness_platform_token.test.identifier + parent_id = harness_platform_token.test.parent_id + apikey_type = harness_platform_token.test.apikey_type + account_id = harness_platform_token.test.account_id + org_id = harness_platform_token.test.org_id + name = harness_platform_token.test.name + apikey_id = harness_platform_token.test.apikey_id + } + `, id, name, parentId, accountId) +} + +func testAccDataSourceTokenProjectLevel(id string, name string, parentId string, accountId string) string { + return fmt.Sprintf(` + resource "harness_platform_organization" "test" { + identifier = "%[1]s" + name = "%[2]s" + } + + resource "harness_platform_project" "test" { + identifier = "%[1]s" + name = "%[2]s" + org_id = harness_platform_organization.test.id + color = "#472848" + } + + resource "harness_platform_apikey" "test" { + identifier = "%[1]s" + name = "%[2]s" + parent_id = "%[3]s" + account_id = "%[4]s" + org_id = harness_platform_organization.test.id + project_id = harness_platform_project.test.id + apikey_type = "USER" + default_time_to_expire_token = 1000000 + } + + resource "harness_platform_apikey" "test" { + identifier = "%[1]s" + name = "%[2]s" + description="Test Description" + parent_id = "%[3]s" + account_id = "%[4]s" + org_id = harness_platform_organization.test.id + project_id = harness_platform_project.test.id + apikey_type = "USER" + apikey_id = harness_platform_apikey.test.id + } + + data "harness_platform_token" "test" { + identifier = harness_platform_token.test.identifier + parent_id = harness_platform_token.test.parent_id + apikey_type = harness_platform_token.test.apikey_type + account_id = harness_platform_token.test.account_id + org_id = harness_platform_token.test.org_id + project_id = harness_platform_token.test.project_id + name = harness_platform_token.test.name + apikey_id = harness_platform_token.test.apikey_id + } + `, id, name, parentId, accountId) +} diff --git a/internal/service/platform/token/resource_token.go b/internal/service/platform/token/resource_token.go new file mode 100644 index 000000000..e6cb257ac --- /dev/null +++ b/internal/service/platform/token/resource_token.go @@ -0,0 +1,336 @@ +package token + +import ( + "context" + "fmt" + "net/http" + "strings" + + "github.com/antihax/optional" + "github.com/harness/harness-go-sdk/harness/nextgen" + "github.com/harness/terraform-provider-harness/helpers" + "github.com/harness/terraform-provider-harness/internal" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func ResourceToken() *schema.Resource { + resource := &schema.Resource{ + Description: "Resource for creating tokens.", + + ReadContext: resourceTokenRead, + CreateContext: resourceTokenCreateOrUpdate, + UpdateContext: resourceTokenCreateOrUpdate, + DeleteContext: resourceTokenDelete, + Importer: MultiLevelResourceImporter, + + Schema: map[string]*schema.Schema{ + "identifier": { + Description: "Identifier of the Token", + Type: schema.TypeString, + Required: true, + }, + "name": { + Description: "Name of the Token", + Type: schema.TypeString, + Required: true, + }, + "apikey_id": { + Description: "Identifier of the API Key", + Type: schema.TypeString, + Required: true, + }, + "apikey_type": { + Description: "Type of the API Key", + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"USER", "SERVICE_ACCOUNT"}, false), + }, + "parent_id": { + Description: "Parent Entity Identifier of the API Key", + Type: schema.TypeString, + Required: true, + }, + "account_id": { + Description: "Account Identifier for the Entity", + Type: schema.TypeString, + Required: true, + }, + "org_id": { + Description: "Organization Identifier for the Entity", + Type: schema.TypeString, + Optional: true, + }, + "project_id": { + Description: "Project Identifier for the Entity", + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{"org_id"}, + }, + "valid_from": { + Description: "This is the time from which the Token is valid. The time is in milliseconds", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "valid_to": { + Description: "This is the time till which the Token is valid. The time is in milliseconds", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "scheduled_expire_time": { + Description: "Scheduled expiry time in milliseconds", + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "valid": { + Description: "Boolean value to indicate if Token is valid or not.", + Type: schema.TypeBool, + Optional: true, + Computed: true, + }, + "description": { + Description: "Description of the Token", + Type: schema.TypeString, + Optional: true, + }, + "email": { + Description: "Email Id of the user who created the Token", + Type: schema.TypeString, + Optional: true, + }, + "username": { + Description: "Name of the user who created the Token", + Type: schema.TypeString, + Optional: true, + }, + "encoded_password": { + Description: "Encoded password of the Token", + Type: schema.TypeString, + Optional: true, + }, + "tags": { + Description: "Tags for the Token", + Type: schema.TypeMap, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + } + + return resource +} + +func resourceTokenRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + + id := d.Get("identifier").(string) + + type_ := d.Get("apikey_type").(string) + parentId := d.Get("parent_id").(string) + apikeyId := d.Get("apikey_id").(string) + + resp, httpResp, err := c.TokenApi.ListAggregatedTokens(ctx, c.AccountId, type_, parentId, apikeyId, &nextgen.TokenApiListAggregatedTokensOpts{ + OrgIdentifier: helpers.BuildField(d, "org_id"), + ProjectIdentifier: helpers.BuildField(d, "project_id"), + Identifiers: optional.NewInterface(id), + }) + + if err != nil { + return helpers.HandleApiError(err, d, httpResp) + } + + if resp.Data.Content != nil && len(resp.Data.Content) == 1 { + readToken(d, resp.Data.Content[0].Token) + } + + return nil +} + +func resourceTokenCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + + var err error + var resp nextgen.ResponseDtoToken + var httpResp *http.Response + + id := d.Id() + token := buildToken(d) + + if id == "" { + _, httpResp, err = c.TokenApi.CreateToken(ctx, c.AccountId, &nextgen.TokenApiCreateTokenOpts{Body: optional.NewInterface(token)}) + if err == nil { + return resourceTokenRead(ctx, d, meta) + } + } else { + resp, httpResp, err = c.TokenApi.UpdateToken(ctx, c.AccountId, id, &nextgen.TokenApiUpdateTokenOpts{Body: optional.NewInterface(token)}) + } + + if err != nil { + return helpers.HandleApiError(err, d, httpResp) + } + + readToken(d, resp.Data) + + return nil +} + +func resourceTokenDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + + id := d.Id() + + type_ := d.Get("apikey_type").(string) + parentId := d.Get("parent_id").(string) + apikeyId := d.Get("apikey_id").(string) + + _, httpResp, err := c.TokenApi.DeleteToken(ctx, id, c.AccountId, type_, parentId, apikeyId, &nextgen.TokenApiDeleteTokenOpts{ + OrgIdentifier: helpers.BuildField(d, "org_id"), + ProjectIdentifier: helpers.BuildField(d, "project_id"), + }) + + if err != nil { + return helpers.HandleApiError(err, d, httpResp) + } + + return nil +} + +func buildToken(d *schema.ResourceData) *nextgen.Token { + token := &nextgen.Token{} + + if attr, ok := d.GetOk("identifier"); ok { + token.Identifier = attr.(string) + } + + if attr, ok := d.GetOk("name"); ok { + token.Name = attr.(string) + } + + if attr, ok := d.GetOk("description"); ok { + token.Description = attr.(string) + } + + if attr, ok := d.GetOk("tags"); ok { + token.Tags = attr.(map[string]string) + } + + if attr, ok := d.GetOk("apikey_id"); ok { + token.ApiKeyIdentifier = attr.(string) + } + + if attr, ok := d.GetOk("apikey_type"); ok { + token.ApiKeyType = attr.(string) + } + + if attr, ok := d.GetOk("parent_id"); ok { + token.ParentIdentifier = attr.(string) + } + + if attr, ok := d.GetOk("valid_from"); ok { + token.ValidFrom = int64(attr.(int)) + } + + if attr, ok := d.GetOk("valid_to"); ok { + token.ValidTo = int64(attr.(int)) + } + + if attr, ok := d.GetOk("valid"); ok { + token.Valid = attr.(bool) + } + + if attr, ok := d.GetOk("scheduled_expire_time"); ok { + token.ScheduledExpireTime = int64(attr.(int)) + } + + if attr, ok := d.GetOk("account_id"); ok { + token.AccountIdentifier = attr.(string) + } + + if attr, ok := d.GetOk("org_id"); ok { + token.OrgIdentifier = attr.(string) + } + + if attr, ok := d.GetOk("project_id"); ok { + token.ProjectIdentifier = attr.(string) + } + + if attr, ok := d.GetOk("email"); ok { + token.Email = attr.(string) + } + + if attr, ok := d.GetOk("username"); ok { + token.Username = attr.(string) + } + + if attr, ok := d.GetOk("encodedPassword"); ok { + token.EncodedPassword = attr.(string) + } + return token +} + +func readToken(d *schema.ResourceData, token *nextgen.Token) { + d.SetId(token.Identifier) + d.Set("name", token.Name) + d.Set("description", token.Description) + d.Set("tags", token.Tags) + d.Set("apikey_id", token.ApiKeyIdentifier) + d.Set("apikey_type", token.ApiKeyType) + d.Set("parent_id", token.ParentIdentifier) + d.Set("valid_from", token.ValidFrom) + d.Set("valid_to", token.ValidTo) + d.Set("valid", token.Valid) + d.Set("scheduled_expire_time", token.ScheduledExpireTime) + d.Set("account_id", token.AccountIdentifier) + d.Set("project_id", token.ProjectIdentifier) + d.Set("org_id", token.OrgIdentifier) + d.Set("email", token.Email) + d.Set("username", token.Username) + d.Set("encodedPassword", token.EncodedPassword) +} + +var MultiLevelResourceImporter = &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + parts := strings.Split(d.Id(), "/") + + partCount := len(parts) + isAccountToken := partCount == 4 + isOrgToken := partCount == 5 + isProjectToken := partCount == 6 + + if isAccountToken { + d.SetId(parts[3]) + d.Set("parent_id", parts[0]) + d.Set("apikey_id", parts[1]) + d.Set("apikey_type", parts[2]) + d.Set("identifier", parts[3]) + return []*schema.ResourceData{d}, nil + } + + if isOrgToken { + d.SetId(parts[4]) + d.Set("org_id", parts[0]) + d.Set("parent_id", parts[1]) + d.Set("apikey_id", parts[2]) + d.Set("apikey_type", parts[3]) + d.Set("identifier", parts[4]) + return []*schema.ResourceData{d}, nil + } + + if isProjectToken { + d.SetId(parts[5]) + d.Set("project_id", parts[1]) + d.Set("org_id", parts[0]) + d.Set("parent_id", parts[2]) + d.Set("apikey_id", parts[3]) + d.Set("apikey_type", parts[4]) + d.Set("identifier", parts[5]) + return []*schema.ResourceData{d}, nil + } + + return nil, fmt.Errorf("invalid identifier: %s", d.Id()) + }, +} diff --git a/internal/service/platform/token/resource_token_test.go b/internal/service/platform/token/resource_token_test.go new file mode 100644 index 000000000..8442d96e9 --- /dev/null +++ b/internal/service/platform/token/resource_token_test.go @@ -0,0 +1,305 @@ +package token_test + +import ( + "fmt" + "os" + "testing" + + "github.com/antihax/optional" + "github.com/harness/harness-go-sdk/harness/nextgen" + "github.com/harness/harness-go-sdk/harness/utils" + "github.com/harness/terraform-provider-harness/internal/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccResourceToken(t *testing.T) { + + id := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + account_id := os.Getenv("HARNESS_ACCOUNT_ID") + parent_id := os.Getenv("HARNESS_PAT_KEY_PARENT_IDENTIFIER") + + tokenName := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + updatedName := tokenName + "updated" + + resourceName := "harness_platform_token.test" + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccTokenDestroy(resourceName), + Steps: []resource.TestStep{ + { + Config: testAccResourceToken(id, tokenName, parent_id, account_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", id), + resource.TestCheckResourceAttr(resourceName, "name", tokenName), + ), + }, + { + Config: testAccResourceToken(id, updatedName, parent_id, account_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", id), + resource.TestCheckResourceAttr(resourceName, "name", updatedName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: AccountResourceImportTokenIdFunc(resourceName), + }, + }, + }) + +} + +func TestAccResourceTokenOrgLevel(t *testing.T) { + + id := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + account_id := os.Getenv("HARNESS_ACCOUNT_ID") + parent_id := os.Getenv("HARNESS_PAT_KEY_PARENT_IDENTIFIER") + + tokenName := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + updatedName := tokenName + "updated" + + resourceName := "harness_platform_token.test" + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccTokenDestroy(resourceName), + Steps: []resource.TestStep{ + { + Config: testOrgResourceToken(id, tokenName, parent_id, account_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", id), + resource.TestCheckResourceAttr(resourceName, "name", tokenName), + ), + }, + { + Config: testOrgResourceToken(id, updatedName, parent_id, account_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", id), + resource.TestCheckResourceAttr(resourceName, "name", updatedName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: OrgResourceImportTokenIdFunc(resourceName), + }, + }, + }) + +} + +func TestAccResourceTokenProjectLevel(t *testing.T) { + + id := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + account_id := os.Getenv("HARNESS_ACCOUNT_ID") + parent_id := os.Getenv("HARNESS_PAT_KEY_PARENT_IDENTIFIER") + + tokenName := fmt.Sprintf("%s_%s", t.Name(), utils.RandStringBytes(5)) + updatedName := tokenName + "updated" + + resourceName := "harness_platform_token.test" + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + CheckDestroy: testAccTokenDestroy(resourceName), + Steps: []resource.TestStep{ + { + Config: testProjectResourceToken(id, tokenName, parent_id, account_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", id), + resource.TestCheckResourceAttr(resourceName, "name", tokenName), + ), + }, + { + Config: testProjectResourceToken(id, updatedName, parent_id, account_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "id", id), + resource.TestCheckResourceAttr(resourceName, "name", updatedName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: ProjectResourceImportTokenIdFunc(resourceName), + }, + }, + }) + +} + +func testAccGetResourceToken(resourceName string, state *terraform.State) (*nextgen.Token, error) { + r := acctest.TestAccGetResource(resourceName, state) + c, ctx := acctest.TestAccGetPlatformClientWithContext() + id := r.Primary.ID + + resp, _, err := c.TokenApi.ListAggregatedTokens(ctx, c.AccountId, r.Primary.Attributes["apikey_type"], r.Primary.Attributes["parent_id"], r.Primary.Attributes["apikey_id"], &nextgen.TokenApiListAggregatedTokensOpts{ + OrgIdentifier: buildField(r, "org_id"), + ProjectIdentifier: buildField(r, "project_id"), + Identifiers: optional.NewInterface(id), + }) + + if err != nil { + return nil, err + } + + if resp.Data == nil || resp.Data.Content == nil || len(resp.Data.Content) == 0 { + return nil, nil + } + + return resp.Data.Content[0].Token, nil +} + +func testAccResourceToken(id string, name string, parentId string, accountId string) string { + return fmt.Sprintf(` + resource "harness_platform_apikey" "test" { + identifier = "%[1]s" + name = "%[2]s" + parent_id = "%[3]s" + account_id = "%[4]s" + apikey_type = "USER" + default_time_to_expire_token = 1000000 + } + + resource "harness_platform_token" "test" { + identifier = "%[1]s" + name = "%[2]s" + description="Test Description" + parent_id = "%[3]s" + account_id = "%[4]s" + apikey_type = "USER" + apikey_id = harness_platform_apikey.test.id + } + `, id, name, parentId, accountId) +} + +func testOrgResourceToken(id string, name string, parentId string, accountId string) string { + return fmt.Sprintf(` + resource "harness_platform_organization" "test" { + identifier = "%[1]s" + name = "%[2]s" + } + + resource "harness_platform_apikey" "test" { + identifier = "%[1]s" + name = "%[2]s" + parent_id = "%[3]s" + account_id = "%[4]s" + org_id = harness_platform_organization.test.id + apikey_type = "USER" + default_time_to_expire_token = 1000000 + } + + resource "harness_platform_token" "test" { + identifier = "%[1]s" + name = "%[2]s" + description="Test Description" + parent_id = "%[3]s" + account_id = "%[4]s" + org_id = harness_platform_organization.test.id + apikey_type = "USER" + apikey_id = harness_platform_apikey.test.id + } + `, id, name, parentId, accountId) +} + +func testProjectResourceToken(id string, name string, parentId string, accountId string) string { + return fmt.Sprintf(` + resource "harness_platform_organization" "test" { + identifier = "%[1]s" + name = "%[2]s" + } + + resource "harness_platform_project" "test" { + identifier = "%[1]s" + name = "%[2]s" + org_id = harness_platform_organization.test.id + color = "#472848" + } + + resource "harness_platform_apikey" "test" { + identifier = "%[1]s" + name = "%[2]s" + parent_id = "%[3]s" + account_id = "%[4]s" + org_id = harness_platform_organization.test.id + project_id = harness_platform_project.test.id + apikey_type = "USER" + default_time_to_expire_token = 1000000 + } + + resource "harness_platform_token" "test" { + identifier = "%[1]s" + name = "%[2]s" + description="Test Description" + parent_id = "%[3]s" + account_id = "%[4]s" + org_id = harness_platform_organization.test.id + project_id = harness_platform_project.test.id + apikey_type = "USER" + apikey_id = harness_platform_apikey.test.id + } + `, id, name, parentId, accountId) +} + +func buildField(r *terraform.ResourceState, field string) optional.String { + if attr, ok := r.Primary.Attributes[field]; ok { + return optional.NewString(attr) + } + return optional.EmptyString() +} + +func testAccTokenDestroy(resourceName string) resource.TestCheckFunc { + return func(state *terraform.State) error { + token, _ := testAccGetResourceToken(resourceName, state) + if token != nil { + return fmt.Errorf("Found token: %s", token.Identifier) + } + + return nil + } +} + +func AccountResourceImportTokenIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + primary := s.RootModule().Resources[resourceName].Primary + id := primary.ID + apikey_id := primary.Attributes["apikey_id"] + parent_id := primary.Attributes["parent_id"] + apikey_type := primary.Attributes["apikey_type"] + return fmt.Sprintf("%s/%s/%s/%s", parent_id, apikey_id, apikey_type, id), nil + } +} + +func OrgResourceImportTokenIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + primary := s.RootModule().Resources[resourceName].Primary + id := primary.ID + orgId := primary.Attributes["org_id"] + apikey_id := primary.Attributes["apikey_id"] + parent_id := primary.Attributes["parent_id"] + apikey_type := primary.Attributes["apikey_type"] + return fmt.Sprintf("%s/%s/%s/%s/%s", orgId, parent_id, apikey_id, apikey_type, id), nil + } +} + +func ProjectResourceImportTokenIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + primary := s.RootModule().Resources[resourceName].Primary + id := primary.ID + orgId := primary.Attributes["org_id"] + projId := primary.Attributes["project_id"] + apikey_id := primary.Attributes["apikey_id"] + parent_id := primary.Attributes["parent_id"] + apikey_type := primary.Attributes["apikey_type"] + return fmt.Sprintf("%s/%s/%s/%s/%s/%s", orgId, projId, parent_id, apikey_id, apikey_type, id), nil + } +}