diff --git a/go.mod b/go.mod index 98257e375..d6f10c085 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,9 @@ module github.com/UpCloudLtd/terraform-provider-upcloud go 1.25.3 require ( - github.com/UpCloudLtd/upcloud-go-api/credentials v0.1.1 + github.com/UpCloudLtd/upcloud-go-api/credentials v0.1.2-0.20260218111517-78b5a1eb8206 github.com/UpCloudLtd/upcloud-go-api/v8 v8.35.0 + github.com/UpCloudLtd/upcloud-go-api/v9 v9.0.0-20260325142902-ff360d09fd8a github.com/hashicorp/go-cty v1.5.0 github.com/hashicorp/go-retryablehttp v0.7.7 github.com/hashicorp/go-uuid v1.0.3 @@ -17,22 +18,24 @@ require ( github.com/hashicorp/terraform-plugin-testing v1.13.0 github.com/stretchr/testify v1.11.1 go.yaml.in/yaml/v3 v3.0.4 - golang.org/x/crypto v0.46.0 - golang.org/x/mod v0.30.0 + golang.org/x/crypto v0.48.0 + golang.org/x/mod v0.33.0 ) require ( al.essio.dev/pkg/shellescape v1.5.1 // indirect github.com/ProtonMail/go-crypto v1.1.6 // indirect github.com/agext/levenshtein v1.2.3 // indirect + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/cloudflare/circl v1.6.3 // indirect github.com/danieljoos/wincred v1.2.2 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/fatih/color v1.16.0 // indirect + github.com/fatih/color v1.18.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.7.0 // indirect + github.com/google/uuid v1.6.0 // 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 @@ -55,6 +58,8 @@ require ( github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.6.0 // indirect + github.com/oapi-codegen/runtime v1.3.0 // indirect github.com/oklog/run v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect @@ -63,11 +68,11 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zalando/go-keyring v0.2.6 // indirect github.com/zclconf/go-cty v1.16.2 // indirect - golang.org/x/net v0.48.0 // indirect + golang.org/x/net v0.51.0 // indirect golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.39.0 // indirect - golang.org/x/text v0.32.0 // indirect - golang.org/x/tools v0.39.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.34.0 // indirect + golang.org/x/tools v0.42.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect google.golang.org/grpc v1.79.3 // indirect diff --git a/go.sum b/go.sum index c1b1c9932..d4ea7b382 100644 --- a/go.sum +++ b/go.sum @@ -6,15 +6,21 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/UpCloudLtd/upcloud-go-api/credentials v0.1.1 h1:eTfQsv58ufALOk9BZ7WbS/i7pMUD11RnYYpRPsz0LdI= -github.com/UpCloudLtd/upcloud-go-api/credentials v0.1.1/go.mod h1:7OtVs2UqtfvjkC1HfE+Oud0MnbMv7qUWnbEgxnTAqts= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= +github.com/UpCloudLtd/upcloud-go-api/credentials v0.1.2-0.20260218111517-78b5a1eb8206 h1:r1Q2sxM6GkJiRrw14gFC9GHk49mh4ngpX+ihFNDZ4ro= +github.com/UpCloudLtd/upcloud-go-api/credentials v0.1.2-0.20260218111517-78b5a1eb8206/go.mod h1:aZoVN4egBMe11BuJWJywm2aF1rZipCQ69VhacEtYm/M= github.com/UpCloudLtd/upcloud-go-api/v8 v8.35.0 h1:AIt07ExXzCaC9YVszkVPT+CteoyXldw0C8DGUMxtjD4= github.com/UpCloudLtd/upcloud-go-api/v8 v8.35.0/go.mod h1:sxG94uNhC31OQH+zK0RhZjVj+PdkhObsNAt5bvq2J8c= +github.com/UpCloudLtd/upcloud-go-api/v9 v9.0.0-20260325142902-ff360d09fd8a h1:NpE95rTV9nasovr8DLZz2Bvhr2Ng3yACNRgfolY9JsI= +github.com/UpCloudLtd/upcloud-go-api/v9 v9.0.0-20260325142902-ff360d09fd8a/go.mod h1:Sy9fWRwKJnUZlN9LwnEwCOG1pgkktR303kD88V38D6E= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= 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/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= @@ -34,8 +40,8 @@ github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5O 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.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= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= @@ -122,6 +128,7 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -149,6 +156,10 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/oapi-codegen/oapi-codegen/v2 v2.6.0 h1:4i+F2cvwBFZeplxCssNdLy3MhNzUD87mI3HnayHZkAU= +github.com/oapi-codegen/oapi-codegen/v2 v2.6.0/go.mod h1:eWHeJSohQJIINJZzzQriVynfGsnlQVh0UkN2UYYcw4Q= +github.com/oapi-codegen/runtime v1.3.0 h1:vyK1zc0gDWWXgk2xoQa4+X4RNNc5SL2RbTpJS/4vMYA= +github.com/oapi-codegen/runtime v1.3.0/go.mod h1:kOdeacKy7t40Rclb1je37ZLFboFxh+YLy0zaPCMibPY= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= @@ -162,9 +173,11 @@ github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= @@ -200,17 +213,17 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= +golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= 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-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -228,23 +241,23 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc 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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 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.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= +golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= diff --git a/internal/service/managedobjectstorage/bucket.go b/internal/service/managedobjectstorage/bucket.go index 496b2e939..58095bb6f 100644 --- a/internal/service/managedobjectstorage/bucket.go +++ b/internal/service/managedobjectstorage/bucket.go @@ -2,11 +2,12 @@ package managedobjectstorage import ( "context" + "fmt" + "net/http" "github.com/UpCloudLtd/terraform-provider-upcloud/internal/utils" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/request" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/service" + v9 "github.com/UpCloudLtd/upcloud-go-api/v9/pkg/upcloud" + "github.com/google/uuid" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -27,7 +28,7 @@ func NewBucketResource() resource.Resource { } type managedObjectStorageBucketResource struct { - client *service.Service + client *v9.ClientWithResponses } func (r *managedObjectStorageBucketResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -36,7 +37,7 @@ func (r *managedObjectStorageBucketResource) Metadata(_ context.Context, req res // Configure adds the provider configured client to the resource. func (r *managedObjectStorageBucketResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - r.client, resp.Diagnostics = utils.GetClientFromProviderData(req.ProviderData) + r.client, resp.Diagnostics = utils.GetV9ClientFromProviderData(req.ProviderData) } type bucketModel struct { @@ -83,10 +84,35 @@ func (r *managedObjectStorageBucketResource) Schema(_ context.Context, _ resourc } } -func setBucketValues(data *bucketModel, bucket *upcloud.ManagedObjectStorageBucketMetrics) { - data.Name = types.StringValue(bucket.Name) - data.TotalObjects = types.Int64Value(int64(bucket.TotalObjects)) - data.TotalSizeBytes = types.Int64Value(int64(bucket.TotalSizeBytes)) +func setBucketValues(data *bucketModel, detail *v9.ObjectStorage2BucketDetailResponse, fallbackName string) { + if detail == nil { + return + } + if detail.Name != nil { + data.Name = types.StringValue(*detail.Name) + } else if fallbackName != "" { + data.Name = types.StringValue(fallbackName) + } + var totalObj int64 + if detail.TotalObjects != nil { + totalObj = int64(*detail.TotalObjects) + } + data.TotalObjects = types.Int64Value(totalObj) + var totalSize int64 + if detail.TotalSizeBytes != nil { + totalSize = *detail.TotalSizeBytes + } + data.TotalSizeBytes = types.Int64Value(totalSize) +} + +func objectStorageAPIErrorDetail(prob *v9.ObjectStorage2ErrorResponse, body []byte) string { + if prob != nil { + return fmt.Sprintf("%s (HTTP %d, type=%s, correlation_id=%s)", prob.Title, prob.Status, prob.Type, prob.CorrelationId) + } + if len(body) > 0 { + return string(body) + } + return "unexpected API response" } func (r *managedObjectStorageBucketResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { @@ -99,12 +125,18 @@ func (r *managedObjectStorageBucketResource) Create(ctx context.Context, req res data.ID = types.StringValue(utils.MarshalID(data.ServiceUUID.ValueString(), data.Name.ValueString())) - apiReq := &request.CreateManagedObjectStorageBucketRequest{ - Name: data.Name.ValueString(), - ServiceUUID: data.ServiceUUID.ValueString(), + svcUUID, err := uuid.Parse(data.ServiceUUID.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Unable to parse service UUID", + utils.ErrorDiagnosticDetail(err), + ) + return } - bucket, err := r.client.CreateManagedObjectStorageBucket(ctx, apiReq) + apiResp, err := r.client.CreateObjectStorageBucketWithResponse(ctx, svcUUID, v9.CreateObjectStorageBucketJSONRequestBody{ + Name: data.Name.ValueString(), + }) if err != nil { resp.Diagnostics.AddError( "Unable to create managed object storage bucket", @@ -112,30 +144,63 @@ func (r *managedObjectStorageBucketResource) Create(ctx context.Context, req res ) return } + if apiResp.StatusCode() != http.StatusCreated || apiResp.JSON201 == nil { + resp.Diagnostics.AddError( + "Unable to create managed object storage bucket", + objectStorageAPIErrorDetail(apiResp.ApplicationproblemJSONDefault, apiResp.Body), + ) + return + } - setBucketValues(&data, &bucket) + setBucketValues(&data, apiResp.JSON201, data.Name.ValueString()) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func getBucket(ctx context.Context, serviceUUID, name string, client *service.Service) (bucket *upcloud.ManagedObjectStorageBucketMetrics, diags diag.Diagnostics) { - buckets, err := client.GetManagedObjectStorageBucketMetrics(ctx, &request.GetManagedObjectStorageBucketMetricsRequest{ - ServiceUUID: serviceUUID, - }) +func getBucket(ctx context.Context, serviceUUID, name string, client *v9.ClientWithResponses) (*v9.ObjectStorage2BucketDetailResponse, diag.Diagnostics) { + var diags diag.Diagnostics + + svcUUID, err := uuid.Parse(serviceUUID) if err != nil { diags.AddError( - "Unable to read managed object storage buckets", + "Unable to parse service UUID", utils.ErrorDiagnosticDetail(err), ) return nil, diags } - for _, b := range buckets { - if b.Name == name { - bucket = &b - break + apiResp, err := client.ListObjectStorageBucketMetricsWithResponse(ctx, svcUUID, nil) + if err != nil { + diags.AddError( + "Unable to read managed object storage buckets", + utils.ErrorDiagnosticDetail(err), + ) + return nil, diags + } + if apiResp.StatusCode() == http.StatusNotFound { + diags.AddError( + "Unable to read managed object storage buckets", + objectStorageAPIErrorDetail(apiResp.ApplicationproblemJSONDefault, apiResp.Body), + ) + return nil, diags + } + if apiResp.StatusCode() != http.StatusOK { + diags.AddError( + "Unable to read managed object storage buckets", + objectStorageAPIErrorDetail(apiResp.ApplicationproblemJSONDefault, apiResp.Body), + ) + return nil, diags + } + if apiResp.JSON200 == nil { + return nil, diags + } + buckets := *apiResp.JSON200 + for i := range buckets { + b := buckets[i] + if b.Name != nil && *b.Name == name { + return &b, diags } } - return bucket, diags + return nil, diags } func (r *managedObjectStorageBucketResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { @@ -162,12 +227,16 @@ func (r *managedObjectStorageBucketResource) Read(ctx context.Context, req resou bucket, diags := getBucket(ctx, serviceUUID, name, r.client) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + if bucket == nil { resp.State.RemoveResource(ctx) return } - setBucketValues(&data, bucket) + setBucketValues(&data, bucket, name) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -189,6 +258,9 @@ func (r *managedObjectStorageBucketResource) Update(ctx context.Context, req res bucket, diags := getBucket(ctx, serviceUUID, name, r.client) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } if bucket == nil { resp.Diagnostics.AddError( "Bucket not found", @@ -197,7 +269,7 @@ func (r *managedObjectStorageBucketResource) Update(ctx context.Context, req res return } - setBucketValues(&data, bucket) + setBucketValues(&data, bucket, name) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -212,20 +284,29 @@ func (r *managedObjectStorageBucketResource) Delete(ctx context.Context, req res return } - if err := r.client.DeleteManagedObjectStorageBucket(ctx, &request.DeleteManagedObjectStorageBucketRequest{ - ServiceUUID: serviceUUID, - Name: name, - }); err != nil { + svcUUID, err := uuid.Parse(serviceUUID) + if err != nil { + resp.Diagnostics.AddError( + "Unable to parse service UUID", + utils.ErrorDiagnosticDetail(err), + ) + return + } + + apiResp, err := r.client.DeleteObjectStorageBucketWithResponse(ctx, svcUUID, name) + if err != nil { resp.Diagnostics.AddError( "Unable to delete managed object storage bucket", utils.ErrorDiagnosticDetail(err), ) + } else if apiResp.StatusCode() < 200 || apiResp.StatusCode() >= 300 { + resp.Diagnostics.AddError( + "Unable to delete managed object storage bucket", + objectStorageAPIErrorDetail(apiResp.ApplicationproblemJSONDefault, apiResp.Body), + ) } - if err := r.client.WaitForManagedObjectStorageBucketDeletion(ctx, &request.WaitForManagedObjectStorageBucketDeletionRequest{ - ServiceUUID: serviceUUID, - Name: name, - }); err != nil { + if err := r.client.WaitForObjectStorageBucketDeletion(ctx, serviceUUID, name); err != nil { resp.Diagnostics.AddError( "The deleted bucket was not removed from the managed object storage service", utils.ErrorDiagnosticDetail(err), diff --git a/internal/service/managedobjectstorage/custom_domain.go b/internal/service/managedobjectstorage/custom_domain.go index 8b1c7b79c..a097f02c1 100644 --- a/internal/service/managedobjectstorage/custom_domain.go +++ b/internal/service/managedobjectstorage/custom_domain.go @@ -2,10 +2,12 @@ package managedobjectstorage import ( "context" + "fmt" + "net/http" "github.com/UpCloudLtd/terraform-provider-upcloud/internal/utils" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/request" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/service" + v9 "github.com/UpCloudLtd/upcloud-go-api/v9/pkg/upcloud" + "github.com/google/uuid" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -28,7 +30,7 @@ func NewCustomDomainResource() resource.Resource { } type managedObjectStorageCustomDomainResource struct { - client *service.Service + client *v9.ClientWithResponses } func (r *managedObjectStorageCustomDomainResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -37,7 +39,7 @@ func (r *managedObjectStorageCustomDomainResource) Metadata(_ context.Context, r // Configure adds the provider configured client to the resource. func (r *managedObjectStorageCustomDomainResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - r.client, resp.Diagnostics = utils.GetClientFromProviderData(req.ProviderData) + r.client, resp.Diagnostics = utils.GetV9ClientFromProviderData(req.ProviderData) } type customDomainModel struct { @@ -89,13 +91,16 @@ func (r *managedObjectStorageCustomDomainResource) Create(ctx context.Context, r data.ID = types.StringValue(utils.MarshalID(data.ServiceUUID.ValueString(), data.DomainName.ValueString())) - apiReq := &request.CreateManagedObjectStorageCustomDomainRequest{ - DomainName: data.DomainName.ValueString(), - Type: data.Type.ValueString(), - ServiceUUID: data.ServiceUUID.ValueString(), + serviceUUID, err := uuid.Parse(data.ServiceUUID.ValueString()) + if err != nil { + resp.Diagnostics.AddError("Invalid service UUID", utils.ErrorDiagnosticDetail(err)) + return } - err := r.client.CreateManagedObjectStorageCustomDomain(ctx, apiReq) + apiResp, err := r.client.AttachObjectStorageCustomDomainWithResponse(ctx, serviceUUID, v9.ObjectStorage2CustomDomainCreate{ + DomainName: data.DomainName.ValueString(), + Type: v9.ObjectStorage2CustomDomainCreateType(data.Type.ValueString()), + }) if err != nil { resp.Diagnostics.AddError( "Unable to create managed object storage custom domain", @@ -103,6 +108,13 @@ func (r *managedObjectStorageCustomDomainResource) Create(ctx context.Context, r ) return } + if apiResp.StatusCode() != http.StatusCreated { + resp.Diagnostics.AddError( + "Unable to create managed object storage custom domain", + fmt.Sprintf("API returned unexpected status %s", apiResp.Status()), + ) + return + } resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -120,32 +132,47 @@ func (r *managedObjectStorageCustomDomainResource) Read(ctx context.Context, req return } - var serviceUUID, domainName string - resp.Diagnostics.Append(utils.UnmarshalIDDiag(data.ID.ValueString(), &serviceUUID, &domainName)...) + var serviceUUIDStr, domainName string + resp.Diagnostics.Append(utils.UnmarshalIDDiag(data.ID.ValueString(), &serviceUUIDStr, &domainName)...) if resp.Diagnostics.HasError() { return } - data.ServiceUUID = types.StringValue(serviceUUID) - customDomain, err := r.client.GetManagedObjectStorageCustomDomain(ctx, &request.GetManagedObjectStorageCustomDomainRequest{ - DomainName: domainName, - ServiceUUID: serviceUUID, - }) + serviceUUID, err := uuid.Parse(serviceUUIDStr) + if err != nil { + resp.Diagnostics.AddError("Invalid service UUID", utils.ErrorDiagnosticDetail(err)) + return + } + + data.ServiceUUID = types.StringValue(serviceUUIDStr) + apiResp, err := r.client.GetObjectStorageCustomDomainWithResponse(ctx, serviceUUID, domainName) if err != nil { - if utils.IsNotFoundError(err) { - resp.State.RemoveResource(ctx) - } else { - resp.Diagnostics.AddError( - "Unable to read managed object storage custom domain details", - utils.ErrorDiagnosticDetail(err), - ) - } + resp.Diagnostics.AddError( + "Unable to read managed object storage custom domain details", + utils.ErrorDiagnosticDetail(err), + ) + return + } + if apiResp.StatusCode() == http.StatusNotFound { + resp.State.RemoveResource(ctx) + return + } + if apiResp.StatusCode() != http.StatusOK { + resp.Diagnostics.AddError( + "Unable to read managed object storage custom domain details", + fmt.Sprintf("API returned unexpected status %s", apiResp.Status()), + ) return } - data.DomainName = types.StringValue(customDomain.DomainName) - data.Type = types.StringValue(customDomain.Type) + customDomain := apiResp.JSON200 + if customDomain.DomainName != nil { + data.DomainName = types.StringValue(*customDomain.DomainName) + } + if customDomain.Type != nil { + data.Type = types.StringValue(*customDomain.Type) + } resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -158,31 +185,48 @@ func (r *managedObjectStorageCustomDomainResource) Update(ctx context.Context, r return } - var serviceUUID, domainName string - resp.Diagnostics.Append(utils.UnmarshalIDDiag(state.ID.ValueString(), &serviceUUID, &domainName)...) + var serviceUUIDStr, domainName string + resp.Diagnostics.Append(utils.UnmarshalIDDiag(state.ID.ValueString(), &serviceUUIDStr, &domainName)...) if resp.Diagnostics.HasError() { return } - customDomain, err := r.client.ModifyManagedObjectStorageCustomDomain(ctx, &request.ModifyManagedObjectStorageCustomDomainRequest{ - DomainName: domainName, - ServiceUUID: serviceUUID, - CustomDomain: request.ModifyCustomDomain{ - DomainName: data.DomainName.ValueString(), - Type: data.Type.ValueString(), - }, + serviceUUID, err := uuid.Parse(serviceUUIDStr) + if err != nil { + resp.Diagnostics.AddError("Invalid service UUID", utils.ErrorDiagnosticDetail(err)) + return + } + + newDomainName := data.DomainName.ValueString() + newType := v9.ObjectStorage2CustomDomainModifyType(data.Type.ValueString()) + apiResp, err := r.client.ModifyObjectStorageCustomDomainWithResponse(ctx, serviceUUID, domainName, v9.ObjectStorage2CustomDomainModify{ + DomainName: &newDomainName, + Type: &newType, }) if err != nil { resp.Diagnostics.AddError( "Unable to modify managed object storage custom domain", utils.ErrorDiagnosticDetail(err), ) + return + } + if apiResp.StatusCode() != http.StatusOK { + resp.Diagnostics.AddError( + "Unable to modify managed object storage custom domain", + fmt.Sprintf("API returned unexpected status %s", apiResp.Status()), + ) + return } + customDomain := apiResp.JSON200 data.ID = types.StringValue(utils.MarshalID(data.ServiceUUID.ValueString(), data.DomainName.ValueString())) - data.DomainName = types.StringValue(customDomain.DomainName) - data.Type = types.StringValue(customDomain.Type) + if customDomain.DomainName != nil { + data.DomainName = types.StringValue(*customDomain.DomainName) + } + if customDomain.Type != nil { + data.Type = types.StringValue(*customDomain.Type) + } resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -190,21 +234,32 @@ func (r *managedObjectStorageCustomDomainResource) Delete(ctx context.Context, r var data customDomainModel resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - var serviceUUID, domainName string - resp.Diagnostics.Append(utils.UnmarshalIDDiag(data.ID.ValueString(), &serviceUUID, &domainName)...) + var serviceUUIDStr, domainName string + resp.Diagnostics.Append(utils.UnmarshalIDDiag(data.ID.ValueString(), &serviceUUIDStr, &domainName)...) if resp.Diagnostics.HasError() { return } - if err := r.client.DeleteManagedObjectStorageCustomDomain(ctx, &request.DeleteManagedObjectStorageCustomDomainRequest{ - ServiceUUID: serviceUUID, - DomainName: domainName, - }); err != nil { + serviceUUID, err := uuid.Parse(serviceUUIDStr) + if err != nil { + resp.Diagnostics.AddError("Invalid service UUID", utils.ErrorDiagnosticDetail(err)) + return + } + + apiResp, err := r.client.DeleteObjectStorageCustomDomainWithResponse(ctx, serviceUUID, domainName) + if err != nil { resp.Diagnostics.AddError( "Unable to delete managed object storage custom domain", utils.ErrorDiagnosticDetail(err), ) + return + } + if apiResp.StatusCode() != http.StatusNoContent { + resp.Diagnostics.AddError( + "Unable to delete managed object storage custom domain", + fmt.Sprintf("API returned unexpected status %s", apiResp.Status()), + ) } } diff --git a/internal/service/managedobjectstorage/regions_data_source.go b/internal/service/managedobjectstorage/regions_data_source.go index 2296bc49f..9cabcdc5c 100644 --- a/internal/service/managedobjectstorage/regions_data_source.go +++ b/internal/service/managedobjectstorage/regions_data_source.go @@ -5,8 +5,7 @@ import ( "time" "github.com/UpCloudLtd/terraform-provider-upcloud/internal/utils" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/request" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/service" + v9 "github.com/UpCloudLtd/upcloud-go-api/v9/pkg/upcloud" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" @@ -22,7 +21,7 @@ var ( ) type regionsDataSource struct { - client *service.Service + client *v9.ClientWithResponses } func (d *regionsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { @@ -30,7 +29,7 @@ func (d *regionsDataSource) Metadata(_ context.Context, req datasource.MetadataR } func (d *regionsDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { - d.client, resp.Diagnostics = utils.GetClientFromProviderData(req.ProviderData) + d.client, resp.Diagnostics = utils.GetV9ClientFromProviderData(req.ProviderData) } type regionsModel struct { @@ -82,7 +81,7 @@ func (d *regionsDataSource) Read(ctx context.Context, req datasource.ReadRequest data.ID = types.StringValue(time.Now().UTC().String()) - regions, err := d.client.GetManagedObjectStorageRegions(ctx, &request.GetManagedObjectStorageRegionsRequest{}) + result, err := d.client.ListObjectStorageRegionsWithResponse(ctx) if err != nil { resp.Diagnostics.AddError( "Unable to read managed object-storage regions", @@ -90,15 +89,27 @@ func (d *regionsDataSource) Read(ctx context.Context, req datasource.ReadRequest ) return } + if result.JSON200 == nil { + resp.Diagnostics.AddError( + "Unable to read managed object-storage regions", + "Empty response received from the API", + ) + return + } + regions := *result.JSON200 data.Regions = make([]regionModel, len(regions)) for i, region := range regions { - data.Regions[i].Name = types.StringValue(region.Name) - data.Regions[i].PrimaryZone = types.StringValue(region.PrimaryZone) + data.Regions[i].Name = types.StringPointerValue(region.Name) + data.Regions[i].PrimaryZone = types.StringPointerValue(region.PrimaryZone) zonesSlice := make([]string, 0) - for _, zone := range region.Zones { - zonesSlice = append(zonesSlice, zone.Name) + if region.Zones != nil { + for _, zone := range *region.Zones { + if zone.Name != nil { + zonesSlice = append(zonesSlice, *zone.Name) + } + } } zones, diags := types.SetValueFrom(ctx, types.StringType, utils.NilAsEmptyList(zonesSlice)) diff --git a/internal/service/managedobjectstorage/user.go b/internal/service/managedobjectstorage/user.go index 6b353ff36..1eb82722c 100644 --- a/internal/service/managedobjectstorage/user.go +++ b/internal/service/managedobjectstorage/user.go @@ -2,11 +2,12 @@ package managedobjectstorage import ( "context" + "fmt" + "net/http" "github.com/UpCloudLtd/terraform-provider-upcloud/internal/utils" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/request" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/service" + v9 "github.com/UpCloudLtd/upcloud-go-api/v9/pkg/upcloud" + "github.com/google/uuid" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -27,7 +28,7 @@ func NewUserResource() resource.Resource { } type managedObjectStorageUserResource struct { - client *service.Service + client *v9.ClientWithResponses } func (r *managedObjectStorageUserResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -36,7 +37,7 @@ func (r *managedObjectStorageUserResource) Metadata(_ context.Context, req resou // Configure adds the provider configured client to the resource. func (r *managedObjectStorageUserResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - r.client, resp.Diagnostics = utils.GetClientFromProviderData(req.ProviderData) + r.client, resp.Diagnostics = utils.GetV9ClientFromProviderData(req.ProviderData) } type userModel struct { @@ -90,12 +91,14 @@ func (r *managedObjectStorageUserResource) Schema(_ context.Context, _ resource. } } -func setUserValues(_ context.Context, data *userModel, user *upcloud.ManagedObjectStorageUser) diag.Diagnostics { +func setUserValues(_ context.Context, data *userModel, user *v9.ObjectStorage2UserDetailResponse) diag.Diagnostics { var respDiagnostics diag.Diagnostics - data.ARN = types.StringValue(user.ARN) - data.CreatedAt = types.StringValue(user.CreatedAt.String()) - data.Username = types.StringValue(user.Username) + data.ARN = types.StringPointerValue(user.Arn) + if user.CreatedAt != nil { + data.CreatedAt = types.StringValue(user.CreatedAt.String()) + } + data.Username = types.StringPointerValue(user.Username) return respDiagnostics } @@ -110,12 +113,18 @@ func (r *managedObjectStorageUserResource) Create(ctx context.Context, req resou data.ID = types.StringValue(utils.MarshalID(data.ServiceUUID.ValueString(), data.Username.ValueString())) - apiReq := &request.CreateManagedObjectStorageUserRequest{ - Username: data.Username.ValueString(), - ServiceUUID: data.ServiceUUID.ValueString(), + svcUUID, err := uuid.Parse(data.ServiceUUID.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Unable to create managed object storage user", + utils.ErrorDiagnosticDetail(err), + ) + return } - user, err := r.client.CreateManagedObjectStorageUser(ctx, apiReq) + apiResp, err := r.client.CreateObjectStorageUserWithResponse(ctx, svcUUID, v9.CreateObjectStorageUserJSONRequestBody{ + Username: data.Username.ValueString(), + }) if err != nil { resp.Diagnostics.AddError( "Unable to create managed object storage user", @@ -123,8 +132,15 @@ func (r *managedObjectStorageUserResource) Create(ctx context.Context, req resou ) return } + if apiResp.JSON201 == nil { + resp.Diagnostics.AddError( + "Unable to create managed object storage user", + utils.ErrorDiagnosticDetail(fmt.Errorf("unexpected response: %s", apiResp.HTTPResponse.Status)), + ) + return + } - resp.Diagnostics.Append(setUserValues(ctx, &data, user)...) + resp.Diagnostics.Append(setUserValues(ctx, &data, apiResp.JSON201)...) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -150,23 +166,36 @@ func (r *managedObjectStorageUserResource) Read(ctx context.Context, req resourc data.ServiceUUID = types.StringValue(serviceUUID) - user, err := r.client.GetManagedObjectStorageUser(ctx, &request.GetManagedObjectStorageUserRequest{ - Username: username, - ServiceUUID: serviceUUID, - }) + svcUUID, err := uuid.Parse(serviceUUID) if err != nil { - if utils.IsNotFoundError(err) { + resp.Diagnostics.AddError( + "Unable to read managed object storage user details", + utils.ErrorDiagnosticDetail(err), + ) + return + } + + apiResp, err := r.client.GetObjectStorageUserWithResponse(ctx, svcUUID, username) + if err != nil { + resp.Diagnostics.AddError( + "Unable to read managed object storage user details", + utils.ErrorDiagnosticDetail(err), + ) + return + } + if apiResp.JSON200 == nil { + if apiResp.HTTPResponse != nil && apiResp.HTTPResponse.StatusCode == http.StatusNotFound { resp.State.RemoveResource(ctx) } else { resp.Diagnostics.AddError( "Unable to read managed object storage user details", - utils.ErrorDiagnosticDetail(err), + utils.ErrorDiagnosticDetail(fmt.Errorf("unexpected response: %s", apiResp.HTTPResponse.Status)), ) } return } - resp.Diagnostics.Append(setUserValues(ctx, &data, user)...) + resp.Diagnostics.Append(setUserValues(ctx, &data, apiResp.JSON200)...) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } @@ -189,10 +218,17 @@ func (r *managedObjectStorageUserResource) Delete(ctx context.Context, req resou return } - if err := r.client.DeleteManagedObjectStorageUser(ctx, &request.DeleteManagedObjectStorageUserRequest{ - ServiceUUID: serviceUUID, - Username: username, - }); err != nil { + svcUUID, err := uuid.Parse(serviceUUID) + if err != nil { + resp.Diagnostics.AddError( + "Unable to delete managed object storage user", + utils.ErrorDiagnosticDetail(err), + ) + return + } + + _, err = r.client.DeleteObjectStorageUserWithResponse(ctx, svcUUID, username) + if err != nil { resp.Diagnostics.AddError( "Unable to delete managed object storage user", utils.ErrorDiagnosticDetail(err), diff --git a/internal/service/managedobjectstorage/user_policy.go b/internal/service/managedobjectstorage/user_policy.go index 62c5b4a80..e8702c325 100644 --- a/internal/service/managedobjectstorage/user_policy.go +++ b/internal/service/managedobjectstorage/user_policy.go @@ -2,11 +2,12 @@ package managedobjectstorage import ( "context" + "fmt" + "net/http" "github.com/UpCloudLtd/terraform-provider-upcloud/internal/utils" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/request" - "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/service" + v9 "github.com/UpCloudLtd/upcloud-go-api/v9/pkg/upcloud" + "github.com/google/uuid" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -26,7 +27,7 @@ func NewUserPolicyResource() resource.Resource { } type managedObjectStorageUserPolicyResource struct { - client *service.Service + client *v9.ClientWithResponses } func (r *managedObjectStorageUserPolicyResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -35,7 +36,7 @@ func (r *managedObjectStorageUserPolicyResource) Metadata(_ context.Context, req // Configure adds the provider configured client to the resource. func (r *managedObjectStorageUserPolicyResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - r.client, resp.Diagnostics = utils.GetClientFromProviderData(req.ProviderData) + r.client, resp.Diagnostics = utils.GetV9ClientFromProviderData(req.ProviderData) } type userPolicyModel struct { @@ -91,13 +92,18 @@ func (r *managedObjectStorageUserPolicyResource) Create(ctx context.Context, req data.ID = types.StringValue(utils.MarshalID(data.ServiceUUID.ValueString(), data.Username.ValueString(), data.Name.ValueString())) - apiReq := &request.AttachManagedObjectStorageUserPolicyRequest{ - ServiceUUID: data.ServiceUUID.ValueString(), - Username: data.Username.ValueString(), - Name: data.Name.ValueString(), + serviceUUID, err := uuid.Parse(data.ServiceUUID.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Unable to create managed object storage user policy", + utils.ErrorDiagnosticDetail(err), + ) + return } - err := r.client.AttachManagedObjectStorageUserPolicy(ctx, apiReq) + apiResp, err := r.client.AttachObjectStorageUserPolicyWithResponse(ctx, serviceUUID, data.Username.ValueString(), v9.AttachObjectStorageUserPolicyJSONRequestBody{ + Name: data.Name.ValueString(), + }) if err != nil { resp.Diagnostics.AddError( "Unable to create managed object storage user policy", @@ -105,13 +111,20 @@ func (r *managedObjectStorageUserPolicyResource) Create(ctx context.Context, req ) return } + if apiResp.StatusCode() >= http.StatusBadRequest { + resp.Diagnostics.AddError( + "Unable to create managed object storage user policy", + fmt.Sprintf("API returned status %s", apiResp.Status()), + ) + return + } resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -func policyExists(policies []upcloud.ManagedObjectStorageUserPolicy, name string) bool { +func policyExists(policies []v9.ObjectStorage2PolicyAttachmentResponse, name string) bool { for _, p := range policies { - if p.Name == name { + if p.Name != nil && *p.Name == name { return true } } @@ -142,23 +155,38 @@ func (r *managedObjectStorageUserPolicyResource) Read(ctx context.Context, req r data.Username = types.StringValue(username) data.Name = types.StringValue(name) - policies, err := r.client.GetManagedObjectStorageUserPolicies(ctx, &request.GetManagedObjectStorageUserPoliciesRequest{ - Username: username, - ServiceUUID: serviceUUID, - }) + svcUUID, err := uuid.Parse(serviceUUID) if err != nil { - if utils.IsNotFoundError(err) { - resp.State.RemoveResource(ctx) - } else { - resp.Diagnostics.AddError( - "Unable to read managed object storage user policies", - utils.ErrorDiagnosticDetail(err), - ) - } + resp.Diagnostics.AddError( + "Unable to read managed object storage user policies", + utils.ErrorDiagnosticDetail(err), + ) + return + } + + apiResp, err := r.client.ListObjectStorageAttachedUserPoliciesWithResponse(ctx, svcUUID, username) + if err != nil { + resp.Diagnostics.AddError( + "Unable to read managed object storage user policies", + utils.ErrorDiagnosticDetail(err), + ) return } - if !policyExists(policies, name) { + if apiResp.StatusCode() == http.StatusNotFound { + resp.State.RemoveResource(ctx) + return + } + + if apiResp.JSON200 == nil { + resp.Diagnostics.AddError( + "Unable to read managed object storage user policies", + fmt.Sprintf("API returned status %s", apiResp.Status()), + ) + return + } + + if !policyExists(*apiResp.JSON200, name) { resp.State.RemoveResource(ctx) } @@ -173,22 +201,35 @@ func (r *managedObjectStorageUserPolicyResource) Delete(ctx context.Context, req var data userPolicyModel resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - var serviceUUID, username, name string - resp.Diagnostics.Append(utils.UnmarshalIDDiag(data.ID.ValueString(), &serviceUUID, &username, &name)...) + var serviceUUIDStr, username, name string + resp.Diagnostics.Append(utils.UnmarshalIDDiag(data.ID.ValueString(), &serviceUUIDStr, &username, &name)...) if resp.Diagnostics.HasError() { return } - if err := r.client.DetachManagedObjectStorageUserPolicy(ctx, &request.DetachManagedObjectStorageUserPolicyRequest{ - ServiceUUID: serviceUUID, - Username: username, - Name: name, - }); err != nil { + serviceUUID, err := uuid.Parse(serviceUUIDStr) + if err != nil { + resp.Diagnostics.AddError( + "Unable to delete managed object storage user policy", + utils.ErrorDiagnosticDetail(err), + ) + return + } + + apiResp, err := r.client.DetachObjectStorageUserPolicyWithResponse(ctx, serviceUUID, username, name) + if err != nil { resp.Diagnostics.AddError( "Unable to delete managed object storage user policy", utils.ErrorDiagnosticDetail(err), ) + return + } + if apiResp.StatusCode() >= http.StatusBadRequest { + resp.Diagnostics.AddError( + "Unable to delete managed object storage user policy", + fmt.Sprintf("API returned status %s", apiResp.Status()), + ) } } diff --git a/internal/utils/client.go b/internal/utils/client.go index 00205bd18..397f59da7 100644 --- a/internal/utils/client.go +++ b/internal/utils/client.go @@ -4,21 +4,47 @@ import ( "fmt" "github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/service" + v9 "github.com/UpCloudLtd/upcloud-go-api/v9/pkg/upcloud" "github.com/hashicorp/terraform-plugin-framework/diag" ) -func GetClientFromProviderData(providerData any) (client *service.Service, diags diag.Diagnostics) { +type ServiceWithV9Client struct { + Service *service.Service + V9Client *v9.ClientWithResponses +} + +func getServiceWithV9ClientFromProviderData(providerData any) (*ServiceWithV9Client, diag.Diagnostics) { + var diags diag.Diagnostics + if providerData == nil { return nil, diags } - client, ok := providerData.(*service.Service) + withV9, ok := providerData.(ServiceWithV9Client) if !ok { diags.AddError( - "Unexpected resource Configure type", - fmt.Sprintf("Expected *service.Service, got: %T. Please report this issue to the provider developers.", providerData), + "Unexpected provider data type", + fmt.Sprintf("Expected ServiceWithV9Client, got: %T. Please report this issue to the provider developers.", providerData), ) } - return client, diags + return &withV9, diags +} + +func GetClientFromProviderData(providerData any) (client *service.Service, diags diag.Diagnostics) { + withV9, diags := getServiceWithV9ClientFromProviderData(providerData) + if diags.HasError() || withV9 == nil { + return nil, diags + } + + return withV9.Service, diags +} + +func GetV9ClientFromProviderData(providerData any) (*v9.ClientWithResponses, diag.Diagnostics) { + withV9, diags := getServiceWithV9ClientFromProviderData(providerData) + if diags.HasError() || withV9 == nil { + return nil, diags + } + + return withV9.V9Client, diags } diff --git a/upcloud/provider.go b/upcloud/provider.go index 27b485d46..c4eed8170 100644 --- a/upcloud/provider.go +++ b/upcloud/provider.go @@ -20,7 +20,9 @@ import ( "github.com/UpCloudLtd/terraform-provider-upcloud/internal/service/server" "github.com/UpCloudLtd/terraform-provider-upcloud/internal/service/servergroup" "github.com/UpCloudLtd/terraform-provider-upcloud/internal/service/storage" + "github.com/UpCloudLtd/terraform-provider-upcloud/internal/utils" "github.com/UpCloudLtd/upcloud-go-api/credentials" + v9 "github.com/UpCloudLtd/upcloud-go-api/v9/pkg/upcloud" retryablehttp "github.com/hashicorp/go-retryablehttp" "github.com/hashicorp/terraform-plugin-framework/datasource" @@ -152,9 +154,20 @@ func (p *upcloudProvider) Configure(ctx context.Context, req provider.ConfigureR tflog.Info(ctx, "UpCloud service connection configured for plugin framework provider", map[string]interface{}{"http_client": fmt.Sprintf("%#v", httpClient), "request_timeout": requestTimeout}) - resp.DataSourceData = service - resp.EphemeralResourceData = service - resp.ResourceData = service + v9client, err := v9.New("", v9.WithCredentials(creds)) + if err != nil { + resp.Diagnostics.AddError("Failed to create V9 client", err.Error()) + return + } + + withV9 := utils.ServiceWithV9Client{ + Service: service, + V9Client: v9client, + } + + resp.DataSourceData = withV9 + resp.EphemeralResourceData = withV9 + resp.ResourceData = withV9 } func (p *upcloudProvider) Resources(_ context.Context) []func() resource.Resource {