From 34f4d58c6bd835acb2d4936a70d207fd7e2c7f1f Mon Sep 17 00:00:00 2001 From: Kevin Gibson Date: Thu, 14 Mar 2024 16:35:14 -0700 Subject: [PATCH] + Usergroup membership --- examples/jumpcloud/usergroup/main.tf | 3 + go.mod | 9 +- go.sum | 23 ++--- internal/provider/usergroups_resource.go | 105 ++++++++++++++++++++++- main.go | 5 -- 5 files changed, 119 insertions(+), 26 deletions(-) diff --git a/examples/jumpcloud/usergroup/main.tf b/examples/jumpcloud/usergroup/main.tf index 2edbe55..3af45c4 100644 --- a/examples/jumpcloud/usergroup/main.tf +++ b/examples/jumpcloud/usergroup/main.tf @@ -17,6 +17,9 @@ provider "jumpcloud" { resource "jumpcloud_usergroup" "example_group" { name = "example-terraform-group" description = "This group was created by Spotnana Terraform Provider!" + members = [ + "kgibson@spotnana.com", + "bgodard@spotnana.com",] } output "group_details" { diff --git a/go.mod b/go.mod index 9b202c4..6041d1c 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 toolchain go1.21.5 require ( - github.com/Spotnana-Tech/sec-jumpcloud-client-go v1.0.3 + github.com/Spotnana-Tech/sec-jumpcloud-client-go v1.0.4-0.20240314225154-916f9eb85585 github.com/hashicorp/terraform-plugin-docs v0.17.0 github.com/hashicorp/terraform-plugin-framework v1.5.0 github.com/hashicorp/terraform-plugin-go v0.20.0 @@ -14,6 +14,7 @@ require ( ) require ( + github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect @@ -27,6 +28,7 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/uuid v1.3.1 // indirect + github.com/hashicorp/cli v1.1.6 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -49,7 +51,7 @@ require ( github.com/imdario/mergo v0.3.15 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/cli v1.1.5 // indirect + github.com/mattn/go-runewidth v0.0.9 // 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.0 // indirect @@ -63,6 +65,8 @@ require ( github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/yuin/goldmark v1.6.0 // indirect + github.com/yuin/goldmark-meta v1.1.0 // indirect github.com/zclconf/go-cty v1.14.1 // indirect golang.org/x/crypto v0.17.0 // indirect golang.org/x/exp v0.0.0-20230809150735-7b3493d9a819 // indirect @@ -74,4 +78,5 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97 // indirect google.golang.org/grpc v1.60.0 // indirect google.golang.org/protobuf v1.31.0 // indirect + gopkg.in/yaml.v2 v2.3.0 // indirect ) diff --git a/go.sum b/go.sum index a1ac633..2010082 100644 --- a/go.sum +++ b/go.sum @@ -4,24 +4,24 @@ github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+ github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.1/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= -github.com/Spotnana-Tech/sec-jumpcloud-client-go v1.0.3 h1:pqf3MQDL5WgH5MFCuk4sSpX5fpURqQfHun/gdvVOuBc= -github.com/Spotnana-Tech/sec-jumpcloud-client-go v1.0.3/go.mod h1:9iUtBe/vjsO9xmFmarSdTM9BiQv9cqlwDu7yJc+bsVo= +github.com/Spotnana-Tech/sec-jumpcloud-client-go v1.0.4-0.20240314213138-3c1a4a0a889e h1:QkH23GLwgzu12N9yiRRhEtRhbqNi4ra/cQzas3ZK3c0= +github.com/Spotnana-Tech/sec-jumpcloud-client-go v1.0.4-0.20240314213138-3c1a4a0a889e/go.mod h1:9iUtBe/vjsO9xmFmarSdTM9BiQv9cqlwDu7yJc+bsVo= +github.com/Spotnana-Tech/sec-jumpcloud-client-go v1.0.4-0.20240314215725-dbdd9ce20aec/go.mod h1:9iUtBe/vjsO9xmFmarSdTM9BiQv9cqlwDu7yJc+bsVo= +github.com/Spotnana-Tech/sec-jumpcloud-client-go v1.0.4-0.20240314225154-916f9eb85585 h1:HYGTRIQm1ZE7GC6tevmbEgHWjLpy8KwItitlJadGUa8= +github.com/Spotnana-Tech/sec-jumpcloud-client-go v1.0.4-0.20240314225154-916f9eb85585/go.mod h1:9iUtBe/vjsO9xmFmarSdTM9BiQv9cqlwDu7yJc+bsVo= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= @@ -39,7 +39,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= @@ -65,7 +64,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/cli v1.1.6 h1:CMOV+/LJfL1tXCOKrgAX0uRKnzjj/mpmqNXloRSy2K8= @@ -120,8 +118,6 @@ github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= @@ -142,12 +138,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 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= @@ -155,7 +149,6 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mitchellh/cli v1.1.5/go.mod h1:v8+iFts2sPIKUV1ltktPXMCC8fumSKFItNcD2cLtRR4= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= 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= @@ -174,7 +167,6 @@ github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= 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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= @@ -195,7 +187,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -216,8 +207,6 @@ github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBv github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA= github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= @@ -244,7 +233,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -303,6 +291,5 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -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= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/provider/usergroups_resource.go b/internal/provider/usergroups_resource.go index 7b42c89..2632024 100644 --- a/internal/provider/usergroups_resource.go +++ b/internal/provider/usergroups_resource.go @@ -3,12 +3,14 @@ package provider import ( "context" "fmt" - "github.com/Spotnana-Tech/sec-jumpcloud-client-go" + jumpcloud "github.com/Spotnana-Tech/sec-jumpcloud-client-go" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" + "slices" ) // Ensure the implementation satisfies the expected interfaces. @@ -36,6 +38,7 @@ type UserGroupResourceModel struct { Type types.String `tfsdk:"type"` Email types.String `tfsdk:"email"` MembershipMethod types.String `tfsdk:"membership_method"` + Members types.Set `tfsdk:"members"` } // Metadata returns the resource type name. @@ -80,6 +83,13 @@ func (r *jcUserGroupsResource) Schema(_ context.Context, _ resource.SchemaReques Description: "Can be STATIC or DYNAMIC_AUTOMATED or DYNAMIC_REVIEW_REQUIRED", MarkdownDescription: "Can be STATIC or DYNAMIC_AUTOMATED or DYNAMIC_REVIEW_REQUIRED", }, + "members": schema.SetAttribute{ + Computed: true, + Optional: true, + Description: "User IDs associated with this group", + MarkdownDescription: "This is a set of user IDs associated with this group.", + ElementType: types.StringType, + }, }, } } @@ -94,6 +104,18 @@ func (r *jcUserGroupsResource) Create(ctx context.Context, req resource.CreateRe return } + // Get the members emails from the plan + var planMemberEmails []string + memberUserEmailSet, _ := plan.Members.ToSetValue(ctx) + diags = memberUserEmailSet.ElementsAs(ctx, &planMemberEmails, false) //nolint:all + + // Get the user ids from the emails + var memberUserIds []string + for _, member := range planMemberEmails { + userId, _ := r.client.GetUserIDFromEmail(member) + memberUserIds = append(memberUserIds, userId) + } + // Cast local model to client model group := jumpcloud.UserGroup{ Name: plan.Name.ValueString(), @@ -111,8 +133,29 @@ func (r *jcUserGroupsResource) Create(ctx context.Context, req resource.CreateRe } tflog.Info(ctx, fmt.Sprintf("Created Jumpcloud User Group: %s", g.Name)) + // Add members + for _, userID := range memberUserIds { + ok, _ := r.client.AddUserToGroup(g.ID, userID) + if !ok { + resp.Diagnostics.AddError( + "Error adding user to group", + "Could not add user to group, unexpected error: "+err.Error(), + ) + return + } + } + // Get the newly created group newGroup, _ := r.client.GetUserGroup(g.ID) + + // Get the members + var memberEmails []attr.Value // This is the terraform structure requirement + members, _ := r.client.GetGroupMembers(newGroup.ID) + for _, member := range members { + email, _ := r.client.GetUserEmailFromID(member.To.ID) + memberEmails = append(memberEmails, types.StringValue(email)) + } + returnedMembers, _ := types.SetValue(types.StringType, memberEmails) // Map response body to schema and populate Computed attribute values plan = UserGroupResourceModel{ ID: types.StringValue(newGroup.ID), @@ -121,6 +164,7 @@ func (r *jcUserGroupsResource) Create(ctx context.Context, req resource.CreateRe Email: types.StringValue(newGroup.Email), Type: types.StringValue(newGroup.Type), MembershipMethod: types.StringValue(newGroup.MembershipMethod), + Members: returnedMembers, } // Set state to fully populated data @@ -151,6 +195,14 @@ func (r *jcUserGroupsResource) Read(ctx context.Context, req resource.ReadReques ) return } + // Get the members + var memberEmails []attr.Value // This is the terraform structure requirement + members, _ := r.client.GetGroupMembers(state.ID.ValueString()) + for _, member := range members { + email, _ := r.client.GetUserEmailFromID(member.To.ID) + memberEmails = append(memberEmails, types.StringValue(email)) + } + returnedMembers, _ := types.SetValue(types.StringType, memberEmails) // Overwrite items with refreshed state state = UserGroupResourceModel{ @@ -160,6 +212,7 @@ func (r *jcUserGroupsResource) Read(ctx context.Context, req resource.ReadReques Type: types.StringValue(group.Type), Email: types.StringValue(group.Email), MembershipMethod: types.StringValue(group.MembershipMethod), + Members: returnedMembers, } // Set refreshed state @@ -181,6 +234,16 @@ func (r *jcUserGroupsResource) Update(ctx context.Context, req resource.UpdateRe return } + // Isolate the members from the plan and state + stateMembers, _ := state.Members.ToSetValue(ctx) + plannedMembers, _ := plan.Members.ToSetValue(ctx) + + // Turn them in to []string + var newMembers []string + plannedMembers.ElementsAs(ctx, &newMembers, false) + var oldMembers []string + stateMembers.ElementsAs(ctx, &oldMembers, false) + // Cast local model to client model groupModification := jumpcloud.UserGroup{ Name: plan.Name.ValueString(), @@ -197,10 +260,49 @@ func (r *jcUserGroupsResource) Update(ctx context.Context, req resource.UpdateRe return } + // TODO if plan member not in current members, add to group + for _, member := range newMembers { + if !slices.Contains(currentMembers, member) { + // Add member to group + ok, _ := r.client.AddUserToGroup(state.ID.ValueString(), member) + if !ok { + resp.Diagnostics.AddError( + "Error Adding User to Group", + "Could not add user to group, unexpected error: "+err.Error(), + ) + return + } + } + + } + // TODO if current member not in plan members, remove from group + for _, member := range oldMembers { + if !slices.Contains(newMembers, member) { + // Remove member from group + ok, _ := r.client.RemoveUserFromGroup(state.ID.ValueString(), member) + if !ok { + resp.Diagnostics.AddError( + "Error Removing User from Group", + "Could not remove user from group, unexpected error: "+err.Error(), + ) + return + } + } + + } // Get the updated group groupstate, err := r.client.GetUserGroup(state.ID.ValueString()) //nolint:all tflog.Info(ctx, fmt.Sprintf("Group Name: %s Group ID: %s", group.Name, group.ID)) + // Get the members + var updatedMemberEmails []attr.Value // This is the terraform structure requirement + updatedMembers, _ := r.client.GetGroupMembers(state.ID.ValueString()) + for _, member := range updatedMembers { + email, _ := r.client.GetUserEmailFromID(member.To.ID) + tflog.Info(ctx, fmt.Sprintf("Member Email: %s", email)) + updatedMemberEmails = append(updatedMemberEmails, types.StringValue(email)) + } + finalMembers, _ := types.SetValue(types.StringType, updatedMemberEmails) // Map response body to schema and populate Computed attribute values plan = UserGroupResourceModel{ ID: types.StringValue(groupstate.ID), @@ -209,6 +311,7 @@ func (r *jcUserGroupsResource) Update(ctx context.Context, req resource.UpdateRe Type: types.StringValue(groupstate.Type), Email: types.StringValue(groupstate.Email), MembershipMethod: types.StringValue(groupstate.MembershipMethod), + Members: finalMembers, } // Set state to fully populated data diff --git a/main.go b/main.go index 3c2b0b5..8ee57c9 100644 --- a/main.go +++ b/main.go @@ -39,11 +39,6 @@ func main() { flag.Parse() opts := providerserver.ServeOpts{ - // TODO: Update this string with the published name of your provider. - // NOTE: This is a placeholder name for local development of the provider. - // Change this to the name of your provider when publishing. - - //Address: "registry.terraform.io/Spotnana-Tech/jumpcloud", Address: "github.com/Spotnana-Tech/terraform-provider-jumpcloud", Debug: debug, }