now using client sdk

This commit is contained in:
Manuel Ganter 2025-11-11 15:25:57 +01:00
parent 51c743fb2b
commit a88de9f2e8
No known key found for this signature in database
11 changed files with 497 additions and 1261 deletions

21
go.mod
View file

@ -3,30 +3,47 @@ module github.com/DevFW-CICD/terraform-provider-edge-connect
go 1.25.3 go 1.25.3
require ( require (
edp.buildth.ing/DevFW-CICD/edge-connect-client/v2 v2.0.2
github.com/hashicorp/terraform-plugin-framework v1.16.1 github.com/hashicorp/terraform-plugin-framework v1.16.1
github.com/hashicorp/terraform-plugin-log v0.9.0 github.com/hashicorp/terraform-plugin-log v0.9.0
) )
require ( require (
github.com/fatih/color v1.15.0 // indirect github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.7.0 // indirect github.com/hashicorp/go-plugin v1.7.0 // indirect
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/terraform-plugin-go v0.29.0 // indirect github.com/hashicorp/terraform-plugin-go v0.29.0 // indirect
github.com/hashicorp/terraform-registry-address v0.4.0 // indirect github.com/hashicorp/terraform-registry-address v0.4.0 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect github.com/hashicorp/yamux v0.1.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/oklog/run v1.1.0 // indirect github.com/oklog/run v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/spf13/cobra v1.10.1 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/viper v1.21.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/net v0.43.0 // indirect golang.org/x/net v0.43.0 // indirect
golang.org/x/sys v0.35.0 // indirect golang.org/x/sys v0.35.0 // indirect
golang.org/x/text v0.28.0 // indirect golang.org/x/text v0.28.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect
google.golang.org/grpc v1.75.1 // indirect google.golang.org/grpc v1.75.1 // indirect
google.golang.org/protobuf v1.36.9 // indirect google.golang.org/protobuf v1.36.9 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )

59
go.sum
View file

@ -1,26 +1,39 @@
edp.buildth.ing/DevFW-CICD/edge-connect-client/v2 v2.0.2 h1:AcHIt5oOevf8NJPDRE/rpWHBWMStMWlq0A+jz7Wd5Oo=
edp.buildth.ing/DevFW-CICD/edge-connect-client/v2 v2.0.2/go.mod h1:nPZ4K4BB7eXyeSrcHXvSPkNZbs+XgmxbDJOM4KhbI1A=
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= 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/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8= github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48=
github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/terraform-plugin-framework v1.16.1 h1:1+zwFm3MEqd/0K3YBB2v9u9DtyYHyEuhVOfeIXbteWA= github.com/hashicorp/terraform-plugin-framework v1.16.1 h1:1+zwFm3MEqd/0K3YBB2v9u9DtyYHyEuhVOfeIXbteWA=
@ -35,8 +48,14 @@ 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/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8=
github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= 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/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 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.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@ -44,19 +63,43 @@ 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.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.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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= 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/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
@ -73,6 +116,8 @@ go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFh
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
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/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -95,5 +140,7 @@ google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View file

@ -1,105 +0,0 @@
package client
import (
"encoding/json"
"fmt"
)
// CreateApp creates a new application
func (c *Client) CreateApp(region string, app App) (*App, error) {
req := AppRequest{
Region: region,
App: app,
}
respBody, err := c.doRequest("POST", "/api/v1/auth/ctrl/CreateApp", req)
if err != nil {
return nil, fmt.Errorf("failed to create app: %w", err)
}
var createdApp App
if err := json.Unmarshal(respBody, &createdApp); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &createdApp, nil
}
// GetApp retrieves an application by key
func (c *Client) GetApp(region string, app App) (*App, error) {
req := ShowAppRequest{
Region: region,
App: &app,
}
respBody, err := c.doRequest("POST", "/api/v1/auth/ctrl/ShowApp", req)
if err != nil {
return nil, fmt.Errorf("failed to get app: %w", err)
}
var apps []App
if err := json.Unmarshal(respBody, &apps); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
if len(apps) == 0 {
return nil, fmt.Errorf("app not found")
}
return &apps[0], nil
}
// ListApps lists all applications
func (c *Client) ListApps(region string, filter *App) ([]App, error) {
req := ShowAppRequest{
Region: region,
App: filter,
}
respBody, err := c.doRequest("POST", "/api/v1/auth/ctrl/ShowApp", req)
if err != nil {
return nil, fmt.Errorf("failed to list apps: %w", err)
}
var apps []App
if err := json.Unmarshal(respBody, &apps); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return apps, nil
}
// UpdateApp updates an existing application
func (c *Client) UpdateApp(region string, app App) (*App, error) {
req := AppRequest{
Region: region,
App: app,
}
respBody, err := c.doRequest("POST", "/api/v1/auth/ctrl/UpdateApp", req)
if err != nil {
return nil, fmt.Errorf("failed to update app: %w", err)
}
var updatedApp App
if err := json.Unmarshal(respBody, &updatedApp); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &updatedApp, nil
}
// DeleteApp deletes an application
func (c *Client) DeleteApp(region string, app App) error {
req := AppRequest{
Region: region,
App: app,
}
_, err := c.doRequest("POST", "/api/v1/auth/ctrl/DeleteApp", req)
if err != nil {
return fmt.Errorf("failed to delete app: %w", err)
}
return nil
}

View file

@ -1,114 +0,0 @@
package client
import (
"encoding/json"
"fmt"
)
// CreateAppInst creates a new application instance
func (c *Client) CreateAppInst(region string, appInst AppInst) (*AppInst, error) {
req := AppInstRequest{
Region: region,
AppInst: appInst,
}
respBody, err := c.doRequest("POST", "/api/v1/auth/ctrl/CreateAppInst", req)
if err != nil {
return nil, fmt.Errorf("failed to create app instance: %w", err)
}
// The API returns an array of messages, but we want the final state
// For now, we'll just return the input appInst as created
// A more sophisticated implementation would parse the messages
var messages []map[string]interface{}
if err := json.Unmarshal(respBody, &messages); err != nil {
// If it's not an array of messages, try to unmarshal as AppInst
var createdAppInst AppInst
if err := json.Unmarshal(respBody, &createdAppInst); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &createdAppInst, nil
}
// Return the input appInst (creation was successful)
return &appInst, nil
}
// GetAppInst retrieves an application instance by key
func (c *Client) GetAppInst(region string, appInst AppInst) (*AppInst, error) {
req := ShowAppInstRequest{
Region: region,
AppInst: &appInst,
}
respBody, err := c.doRequest("POST", "/api/v1/auth/ctrl/ShowAppInst", req)
if err != nil {
return nil, fmt.Errorf("failed to get app instance: %w", err)
}
var appInsts []AppInst
if err := json.Unmarshal(respBody, &appInsts); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
if len(appInsts) == 0 {
return nil, fmt.Errorf("app instance not found")
}
return &appInsts[0], nil
}
// ListAppInsts lists all application instances
func (c *Client) ListAppInsts(region string, filter *AppInst) ([]AppInst, error) {
req := ShowAppInstRequest{
Region: region,
AppInst: filter,
}
respBody, err := c.doRequest("POST", "/api/v1/auth/ctrl/ShowAppInst", req)
if err != nil {
return nil, fmt.Errorf("failed to list app instances: %w", err)
}
var appInsts []AppInst
if err := json.Unmarshal(respBody, &appInsts); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return appInsts, nil
}
// UpdateAppInst updates an existing application instance
func (c *Client) UpdateAppInst(region string, appInst AppInst) (*AppInst, error) {
req := AppInstRequest{
Region: region,
AppInst: appInst,
}
respBody, err := c.doRequest("POST", "/api/v1/auth/ctrl/UpdateAppInst", req)
if err != nil {
return nil, fmt.Errorf("failed to update app instance: %w", err)
}
var updatedAppInst AppInst
if err := json.Unmarshal(respBody, &updatedAppInst); err != nil {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}
return &updatedAppInst, nil
}
// DeleteAppInst deletes an application instance
func (c *Client) DeleteAppInst(region string, appInst AppInst) error {
req := AppInstRequest{
Region: region,
AppInst: appInst,
}
_, err := c.doRequest("POST", "/api/v1/auth/ctrl/DeleteAppInst", req)
if err != nil {
return fmt.Errorf("failed to delete app instance: %w", err)
}
return nil
}

View file

@ -1,81 +0,0 @@
package client
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// Client is the API client for Edge Connect
type Client struct {
BaseURL string
HTTPClient *http.Client
Token string
Username string
Password string
}
// NewClient creates a new Edge Connect API client
func NewClient(baseURL, token, username, password string) *Client {
return &Client{
BaseURL: baseURL,
HTTPClient: &http.Client{
Timeout: time.Second * 30,
},
Token: token,
Username: username,
Password: password,
}
}
// doRequest performs an HTTP request with authentication
func (c *Client) doRequest(method, path string, body interface{}) ([]byte, error) {
var reqBody io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("failed to marshal request body: %w", err)
}
reqBody = bytes.NewBuffer(jsonBody)
}
req, err := http.NewRequest(method, c.BaseURL+path, reqBody)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", "application/json")
// Add authentication
if c.Token != "" {
req.Header.Set("Authorization", "Bearer "+c.Token)
} else if c.Username != "" && c.Password != "" {
req.SetBasicAuth(c.Username, c.Password)
}
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(respBody))
}
return respBody, nil
}
// HealthCheck performs a health check on the API
func (c *Client) HealthCheck() error {
_, err := c.doRequest("GET", "/api/v1/", nil)
return err
}

View file

@ -1,82 +0,0 @@
package client
// App represents an application specification
type App struct {
Key struct {
Organization string `json:"organization"`
Name string `json:"name"`
Version string `json:"version"`
} `json:"key"`
Region string `json:"region,omitempty"`
ImageType string `json:"image_type,omitempty"`
ImagePath string `json:"image_path,omitempty"`
DefaultFlavor string `json:"default_flavor,omitempty"`
Deployment string `json:"deployment,omitempty"`
DeploymentManifest string `json:"deployment_manifest,omitempty"`
AccessPorts string `json:"access_ports,omitempty"`
Annotations string `json:"annotations,omitempty"`
Configs []Config `json:"configs,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
DeletePrepare bool `json:"delete_prepare,omitempty"`
}
// Config represents a configuration item
type Config struct {
Kind string `json:"kind,omitempty"`
Config string `json:"config,omitempty"`
}
// AppInst represents an application instance
type AppInst struct {
Key struct {
AppKey struct {
Organization string `json:"organization"`
Name string `json:"name"`
Version string `json:"version"`
} `json:"app_key"`
ClusterInstKey struct {
CloudletKey struct {
Organization string `json:"organization"`
Name string `json:"name"`
} `json:"cloudlet_key"`
Organization string `json:"organization"`
} `json:"cluster_inst_key"`
} `json:"key"`
Cloudlet string `json:"cloudlet,omitempty"`
Flavor string `json:"flavor,omitempty"`
RealClusterName string `json:"real_cluster_name,omitempty"`
State string `json:"state,omitempty"`
RuntimeInfo string `json:"runtime_info,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
Uri string `json:"uri,omitempty"`
Liveness string `json:"liveness,omitempty"`
PowerState string `json:"power_state,omitempty"`
Configs []Config `json:"configs,omitempty"`
DeletePrepare bool `json:"delete_prepare,omitempty"`
}
// AppRequest represents a request to manage App resources
type AppRequest struct {
Region string `json:"region,omitempty"`
App App `json:"app"`
}
// AppInstRequest represents a request to manage AppInst resources
type AppInstRequest struct {
Region string `json:"region,omitempty"`
AppInst AppInst `json:"appinst"`
}
// ShowAppRequest represents a request to list/show apps
type ShowAppRequest struct {
Region string `json:"region,omitempty"`
App *App `json:"app,omitempty"`
}
// ShowAppInstRequest represents a request to list/show app instances
type ShowAppInstRequest struct {
Region string `json:"region,omitempty"`
AppInst *AppInst `json:"appinst,omitempty"`
}

View file

@ -4,174 +4,111 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/DevFW-CICD/terraform-provider-edge-connect/internal/client"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
edgeclient "edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/sdk/edgeconnect"
) )
// Ensure the implementation satisfies the expected interfaces. var _ datasource.DataSource = &AppDataSource{}
var (
_ datasource.DataSource = &appDataSource{}
_ datasource.DataSourceWithConfigure = &appDataSource{}
)
// NewAppDataSource is a helper function to simplify the provider implementation.
func NewAppDataSource() datasource.DataSource { func NewAppDataSource() datasource.DataSource {
return &appDataSource{} return &AppDataSource{}
} }
// appDataSource is the data source implementation. type AppDataSource struct {
type appDataSource struct { client *edgeclient.Client
client *client.Client
} }
// appDataSourceModel maps the data source schema data. type AppDataSourceModel struct {
type appDataSourceModel struct { Id types.String `tfsdk:"id"`
ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"`
Region types.String `tfsdk:"region"` Description types.String `tfsdk:"description"`
Organization types.String `tfsdk:"organization"` Version types.String `tfsdk:"version"`
Name types.String `tfsdk:"name"` Status types.String `tfsdk:"status"`
Version types.String `tfsdk:"version"`
ImageType types.String `tfsdk:"image_type"`
ImagePath types.String `tfsdk:"image_path"`
DefaultFlavor types.String `tfsdk:"default_flavor"`
Deployment types.String `tfsdk:"deployment"`
DeploymentManifest types.String `tfsdk:"deployment_manifest"`
AccessPorts types.String `tfsdk:"access_ports"`
Annotations types.String `tfsdk:"annotations"`
CreatedAt types.String `tfsdk:"created_at"`
UpdatedAt types.String `tfsdk:"updated_at"`
} }
// Metadata returns the data source type name. func (d *AppDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
func (d *appDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_app" resp.TypeName = req.ProviderTypeName + "_app"
} }
// Schema defines the schema for the data source. func (d *AppDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
func (d *appDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{ resp.Schema = schema.Schema{
Description: "Fetches an Edge Connect application specification.", MarkdownDescription: "App data source",
Attributes: map[string]schema.Attribute{ Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{ "id": schema.StringAttribute{
Description: "The unique identifier for the app (format: region/organization/name/version).", MarkdownDescription: "App identifier",
Computed: true, Required: true,
},
"region": schema.StringAttribute{
Description: "The region where the app is deployed (e.g., 'EU').",
Required: true,
},
"organization": schema.StringAttribute{
Description: "The organization that owns the app.",
Required: true,
}, },
"name": schema.StringAttribute{ "name": schema.StringAttribute{
Description: "The name of the application.", MarkdownDescription: "App name",
Required: true, Computed: true,
},
"description": schema.StringAttribute{
MarkdownDescription: "App description",
Computed: true,
}, },
"version": schema.StringAttribute{ "version": schema.StringAttribute{
Description: "The version of the application.", MarkdownDescription: "App version",
Required: true, Computed: true,
}, },
"image_type": schema.StringAttribute{ "status": schema.StringAttribute{
Description: "The type of image (e.g., 'Docker').", MarkdownDescription: "App status",
Computed: true, Computed: true,
},
"image_path": schema.StringAttribute{
Description: "The path to the container image.",
Computed: true,
},
"default_flavor": schema.StringAttribute{
Description: "The default flavor for the app.",
Computed: true,
},
"deployment": schema.StringAttribute{
Description: "The deployment type (e.g., 'kubernetes').",
Computed: true,
},
"deployment_manifest": schema.StringAttribute{
Description: "The Kubernetes deployment manifest (YAML).",
Computed: true,
},
"access_ports": schema.StringAttribute{
Description: "The access ports in format 'protocol:port'.",
Computed: true,
},
"annotations": schema.StringAttribute{
Description: "Annotations for the app.",
Computed: true,
},
"created_at": schema.StringAttribute{
Description: "The timestamp when the app was created.",
Computed: true,
},
"updated_at": schema.StringAttribute{
Description: "The timestamp when the app was last updated.",
Computed: true,
}, },
}, },
} }
} }
// Configure adds the provider configured client to the data source. func (d *AppDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
func (d *appDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil { if req.ProviderData == nil {
return return
} }
client, ok := req.ProviderData.(*client.Client) client, ok := req.ProviderData.(*edgeclient.Client)
if !ok { if !ok {
resp.Diagnostics.AddError( resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type", "Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), fmt.Sprintf("Expected *edgeclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
) )
return return
} }
d.client = client d.client = client
} }
// Read refreshes the Terraform state with the latest data. func (d *AppDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
func (d *appDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var data AppDataSourceModel
var config appDataSourceModel
diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Get app from API appKey := edgeclient.AppKey{
app := client.App{} Organization: "default",
app.Key.Organization = config.Organization.ValueString() Name: data.Id.ValueString(),
app.Key.Name = config.Name.ValueString() Version: "",
app.Key.Version = config.Version.ValueString() }
readApp, err := d.client.GetApp(config.Region.ValueString(), app) app, err := d.client.ShowApp(ctx, appKey, "default")
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app %s, got error: %s", data.Id.ValueString(), err))
"Error reading app",
"Could not read app: "+err.Error(),
)
return return
} }
// Map response to data source model data.Name = types.StringValue(app.Key.Name)
config.ID = types.StringValue(fmt.Sprintf("%s/%s/%s/%s", data.Description = types.StringValue("")
config.Region.ValueString(), data.Version = types.StringValue(app.Key.Version)
readApp.Key.Organization, data.Status = types.StringValue("")
readApp.Key.Name,
readApp.Key.Version))
config.ImageType = types.StringValue(readApp.ImageType)
config.ImagePath = types.StringValue(readApp.ImagePath)
config.DefaultFlavor = types.StringValue(readApp.DefaultFlavor)
config.Deployment = types.StringValue(readApp.Deployment)
config.DeploymentManifest = types.StringValue(readApp.DeploymentManifest)
config.AccessPorts = types.StringValue(readApp.AccessPorts)
config.Annotations = types.StringValue(readApp.Annotations)
config.CreatedAt = types.StringValue(readApp.CreatedAt)
config.UpdatedAt = types.StringValue(readApp.UpdatedAt)
diags = resp.State.Set(ctx, &config) tflog.Trace(ctx, "read an app data source")
resp.Diagnostics.Append(diags...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
} }

View file

@ -4,7 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/DevFW-CICD/terraform-provider-edge-connect/internal/client"
"github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema"
@ -12,300 +11,212 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
edgeclient "edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/sdk/edgeconnect"
) )
// Ensure the implementation satisfies the expected interfaces. var _ resource.Resource = &AppResource{}
var ( var _ resource.ResourceWithImportState = &AppResource{}
_ resource.Resource = &appResource{}
_ resource.ResourceWithConfigure = &appResource{}
_ resource.ResourceWithImportState = &appResource{}
)
// NewAppResource is a helper function to simplify the provider implementation.
func NewAppResource() resource.Resource { func NewAppResource() resource.Resource {
return &appResource{} return &AppResource{}
} }
// appResource is the resource implementation. type AppResource struct {
type appResource struct { client *edgeclient.Client
client *client.Client
} }
// appResourceModel maps the resource schema data. type AppResourceModel struct {
type appResourceModel struct { Id types.String `tfsdk:"id"`
ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"`
Region types.String `tfsdk:"region"` Description types.String `tfsdk:"description"`
Organization types.String `tfsdk:"organization"` Version types.String `tfsdk:"version"`
Name types.String `tfsdk:"name"` Status types.String `tfsdk:"status"`
Version types.String `tfsdk:"version"`
ImageType types.String `tfsdk:"image_type"`
ImagePath types.String `tfsdk:"image_path"`
DefaultFlavor types.String `tfsdk:"default_flavor"`
Deployment types.String `tfsdk:"deployment"`
DeploymentManifest types.String `tfsdk:"deployment_manifest"`
AccessPorts types.String `tfsdk:"access_ports"`
Annotations types.String `tfsdk:"annotations"`
CreatedAt types.String `tfsdk:"created_at"`
UpdatedAt types.String `tfsdk:"updated_at"`
} }
// Metadata returns the resource type name. func (r *AppResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
func (r *appResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_app" resp.TypeName = req.ProviderTypeName + "_app"
} }
// Schema defines the schema for the resource. func (r *AppResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
func (r *appResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{ resp.Schema = schema.Schema{
Description: "Manages an Edge Connect application specification.", MarkdownDescription: "App resource",
Attributes: map[string]schema.Attribute{ Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{ "id": schema.StringAttribute{
Description: "The unique identifier for the app (format: region/organization/name/version).", Computed: true,
Computed: true, MarkdownDescription: "App identifier",
PlanModifiers: []planmodifier.String{ PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(), stringplanmodifier.UseStateForUnknown(),
}, },
}, },
"region": schema.StringAttribute{
Description: "The region where the app is deployed (e.g., 'EU').",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"organization": schema.StringAttribute{
Description: "The organization that owns the app.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"name": schema.StringAttribute{ "name": schema.StringAttribute{
Description: "The name of the application.", MarkdownDescription: "App name",
Required: true, Required: true,
PlanModifiers: []planmodifier.String{ },
stringplanmodifier.RequiresReplace(), "description": schema.StringAttribute{
}, MarkdownDescription: "App description",
Optional: true,
}, },
"version": schema.StringAttribute{ "version": schema.StringAttribute{
Description: "The version of the application.", MarkdownDescription: "App version",
Required: true, Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
}, },
"image_type": schema.StringAttribute{ "status": schema.StringAttribute{
Description: "The type of image (e.g., 'Docker').", MarkdownDescription: "App status",
Required: true, Computed: true,
},
"image_path": schema.StringAttribute{
Description: "The path to the container image.",
Required: true,
},
"default_flavor": schema.StringAttribute{
Description: "The default flavor for the app (e.g., 'EU.small', 'EU.medium', 'EU.big', 'EU.large').",
Optional: true,
},
"deployment": schema.StringAttribute{
Description: "The deployment type (e.g., 'kubernetes').",
Required: true,
},
"deployment_manifest": schema.StringAttribute{
Description: "The Kubernetes deployment manifest (YAML).",
Optional: true,
},
"access_ports": schema.StringAttribute{
Description: "The access ports in format 'protocol:port' (e.g., 'tcp:80,tcp:443').",
Optional: true,
},
"annotations": schema.StringAttribute{
Description: "Annotations for the app.",
Optional: true,
},
"created_at": schema.StringAttribute{
Description: "The timestamp when the app was created.",
Computed: true,
},
"updated_at": schema.StringAttribute{
Description: "The timestamp when the app was last updated.",
Computed: true,
}, },
}, },
} }
} }
// Configure adds the provider configured client to the resource. func (r *AppResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
func (r *appResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil { if req.ProviderData == nil {
return return
} }
client, ok := req.ProviderData.(*client.Client) client, ok := req.ProviderData.(*edgeclient.Client)
if !ok { if !ok {
resp.Diagnostics.AddError( resp.Diagnostics.AddError(
"Unexpected Resource Configure Type", "Unexpected Resource Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), fmt.Sprintf("Expected *edgeclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
) )
return return
} }
r.client = client r.client = client
} }
// Create creates the resource and sets the initial Terraform state. func (r *AppResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
func (r *appResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data AppResourceModel
var plan appResourceModel
diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Create new app appInput := &edgeclient.NewAppInput{
app := client.App{ Region: "default",
Region: plan.Region.ValueString(), App: edgeclient.App{
ImageType: plan.ImageType.ValueString(), Key: edgeclient.AppKey{
ImagePath: plan.ImagePath.ValueString(), Organization: "default",
DefaultFlavor: plan.DefaultFlavor.ValueString(), Name: data.Name.ValueString(),
Deployment: plan.Deployment.ValueString(), Version: data.Version.ValueString(),
DeploymentManifest: plan.DeploymentManifest.ValueString(), },
AccessPorts: plan.AccessPorts.ValueString(), Deployment: "kubernetes",
Annotations: plan.Annotations.ValueString(), ImageType: "docker",
ImagePath: "nginx:latest",
},
} }
app.Key.Organization = plan.Organization.ValueString()
app.Key.Name = plan.Name.ValueString()
app.Key.Version = plan.Version.ValueString()
createdApp, err := r.client.CreateApp(plan.Region.ValueString(), app) err := r.client.CreateApp(ctx, appInput)
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create app, got error: %s", err))
"Error creating app",
"Could not create app: "+err.Error(),
)
return return
} }
// Map response body to schema and populate Computed attribute values data.Id = types.StringValue(appInput.App.Key.Name)
plan.ID = types.StringValue(fmt.Sprintf("%s/%s/%s/%s", data.Name = types.StringValue(appInput.App.Key.Name)
plan.Region.ValueString(), data.Description = types.StringValue("")
createdApp.Key.Organization, data.Version = types.StringValue(appInput.App.Key.Version)
createdApp.Key.Name, data.Status = types.StringValue("created")
createdApp.Key.Version))
plan.CreatedAt = types.StringValue(createdApp.CreatedAt)
plan.UpdatedAt = types.StringValue(createdApp.UpdatedAt)
tflog.Trace(ctx, "created app resource") tflog.Trace(ctx, "created an app resource")
diags = resp.State.Set(ctx, plan) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
resp.Diagnostics.Append(diags...)
} }
// Read refreshes the Terraform state with the latest data. func (r *AppResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
func (r *appResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data AppResourceModel
var state appResourceModel
diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Get app from API appKey := edgeclient.AppKey{
app := client.App{} Organization: "default",
app.Key.Organization = state.Organization.ValueString() Name: data.Id.ValueString(),
app.Key.Name = state.Name.ValueString() Version: data.Version.ValueString(),
app.Key.Version = state.Version.ValueString() }
readApp, err := r.client.GetApp(state.Region.ValueString(), app) app, err := r.client.ShowApp(ctx, appKey, "default")
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app %s, got error: %s", data.Id.ValueString(), err))
"Error reading app",
"Could not read app: "+err.Error(),
)
return return
} }
// Map response to state data.Name = types.StringValue(app.Key.Name)
state.ImageType = types.StringValue(readApp.ImageType) data.Description = types.StringValue("")
state.ImagePath = types.StringValue(readApp.ImagePath) data.Version = types.StringValue(app.Key.Version)
state.DefaultFlavor = types.StringValue(readApp.DefaultFlavor) data.Status = types.StringValue("")
state.Deployment = types.StringValue(readApp.Deployment)
state.DeploymentManifest = types.StringValue(readApp.DeploymentManifest)
state.AccessPorts = types.StringValue(readApp.AccessPorts)
state.Annotations = types.StringValue(readApp.Annotations)
state.CreatedAt = types.StringValue(readApp.CreatedAt)
state.UpdatedAt = types.StringValue(readApp.UpdatedAt)
diags = resp.State.Set(ctx, &state) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
resp.Diagnostics.Append(diags...)
} }
// Update updates the resource and sets the updated Terraform state on success. func (r *AppResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
func (r *appResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var data AppResourceModel
var plan appResourceModel
diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Update app updateInput := &edgeclient.UpdateAppInput{
app := client.App{ Region: "default",
Region: plan.Region.ValueString(), App: edgeclient.App{
ImageType: plan.ImageType.ValueString(), Key: edgeclient.AppKey{
ImagePath: plan.ImagePath.ValueString(), Organization: "default",
DefaultFlavor: plan.DefaultFlavor.ValueString(), Name: data.Name.ValueString(),
Deployment: plan.Deployment.ValueString(), Version: data.Version.ValueString(),
DeploymentManifest: plan.DeploymentManifest.ValueString(), },
AccessPorts: plan.AccessPorts.ValueString(), Deployment: "kubernetes",
Annotations: plan.Annotations.ValueString(), ImageType: "docker",
ImagePath: "nginx:latest",
},
} }
app.Key.Organization = plan.Organization.ValueString()
app.Key.Name = plan.Name.ValueString()
app.Key.Version = plan.Version.ValueString()
updatedApp, err := r.client.UpdateApp(plan.Region.ValueString(), app) err := r.client.UpdateApp(ctx, updateInput)
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update app, got error: %s", err))
"Error updating app",
"Could not update app: "+err.Error(),
)
return return
} }
// Update computed attributes data.Name = types.StringValue(updateInput.App.Key.Name)
plan.UpdatedAt = types.StringValue(updatedApp.UpdatedAt) data.Description = types.StringValue("")
data.Version = types.StringValue(updateInput.App.Key.Version)
data.Status = types.StringValue("updated")
diags = resp.State.Set(ctx, plan) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
resp.Diagnostics.Append(diags...)
} }
// Delete deletes the resource and removes the Terraform state on success. func (r *AppResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
func (r *appResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var data AppResourceModel
var state appResourceModel
diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Delete app appKey := edgeclient.AppKey{
app := client.App{} Organization: "default",
app.Key.Organization = state.Organization.ValueString() Name: data.Id.ValueString(),
app.Key.Name = state.Name.ValueString() Version: data.Version.ValueString(),
app.Key.Version = state.Version.ValueString() }
err := r.client.DeleteApp(state.Region.ValueString(), app) err := r.client.DeleteApp(ctx, appKey, "default")
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete app, got error: %s", err))
"Error deleting app",
"Could not delete app: "+err.Error(),
)
return return
} }
} }
// ImportState imports the resource state. func (r *AppResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
func (r *appResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
// Import format: region/organization/name/version
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
} }

View file

@ -4,201 +4,120 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/DevFW-CICD/terraform-provider-edge-connect/internal/client"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
edgeclient "edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/sdk/edgeconnect"
) )
// Ensure the implementation satisfies the expected interfaces. var _ datasource.DataSource = &AppInstanceDataSource{}
var (
_ datasource.DataSource = &appInstDataSource{}
_ datasource.DataSourceWithConfigure = &appInstDataSource{}
)
// NewAppInstDataSource is a helper function to simplify the provider implementation. func NewAppInstanceDataSource() datasource.DataSource {
func NewAppInstDataSource() datasource.DataSource { return &AppInstanceDataSource{}
return &appInstDataSource{}
} }
// appInstDataSource is the data source implementation. type AppInstanceDataSource struct {
type appInstDataSource struct { client *edgeclient.Client
client *client.Client
} }
// appInstDataSourceModel maps the data source schema data. type AppInstanceDataSourceModel struct {
type appInstDataSourceModel struct { Id types.String `tfsdk:"id"`
ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"`
Region types.String `tfsdk:"region"` AppId types.String `tfsdk:"app_id"`
AppOrganization types.String `tfsdk:"app_organization"` Description types.String `tfsdk:"description"`
AppName types.String `tfsdk:"app_name"` Config types.String `tfsdk:"config"`
AppVersion types.String `tfsdk:"app_version"` Status types.String `tfsdk:"status"`
CloudletOrganization types.String `tfsdk:"cloudlet_organization"`
CloudletName types.String `tfsdk:"cloudlet_name"`
ClusterOrganization types.String `tfsdk:"cluster_organization"`
Cloudlet types.String `tfsdk:"cloudlet"`
Flavor types.String `tfsdk:"flavor"`
RealClusterName types.String `tfsdk:"real_cluster_name"`
State types.String `tfsdk:"state"`
RuntimeInfo types.String `tfsdk:"runtime_info"`
Uri types.String `tfsdk:"uri"`
Liveness types.String `tfsdk:"liveness"`
PowerState types.String `tfsdk:"power_state"`
CreatedAt types.String `tfsdk:"created_at"`
UpdatedAt types.String `tfsdk:"updated_at"`
} }
// Metadata returns the data source type name. func (d *AppInstanceDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
func (d *appInstDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_app_instance"
resp.TypeName = req.ProviderTypeName + "_appinst"
} }
// Schema defines the schema for the data source. func (d *AppInstanceDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
func (d *appInstDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{ resp.Schema = schema.Schema{
Description: "Fetches an Edge Connect application instance.", MarkdownDescription: "AppInstance data source",
Attributes: map[string]schema.Attribute{ Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{ "id": schema.StringAttribute{
Description: "The unique identifier for the app instance.", MarkdownDescription: "AppInstance identifier",
Computed: true, Required: true,
}, },
"region": schema.StringAttribute{ "name": schema.StringAttribute{
Description: "The region where the app instance is deployed (e.g., 'EU').", MarkdownDescription: "AppInstance name",
Required: true, Computed: true,
}, },
"app_organization": schema.StringAttribute{ "app_id": schema.StringAttribute{
Description: "The organization that owns the app.", MarkdownDescription: "Associated App ID",
Required: true, Computed: true,
}, },
"app_name": schema.StringAttribute{ "description": schema.StringAttribute{
Description: "The name of the application.", MarkdownDescription: "AppInstance description",
Required: true, Computed: true,
}, },
"app_version": schema.StringAttribute{ "config": schema.StringAttribute{
Description: "The version of the application.", MarkdownDescription: "AppInstance configuration",
Required: true, Computed: true,
}, },
"cloudlet_organization": schema.StringAttribute{ "status": schema.StringAttribute{
Description: "The organization that owns the cloudlet.", MarkdownDescription: "AppInstance status",
Required: true, Computed: true,
},
"cloudlet_name": schema.StringAttribute{
Description: "The name of the cloudlet.",
Required: true,
},
"cluster_organization": schema.StringAttribute{
Description: "The organization that owns the cluster.",
Required: true,
},
"cloudlet": schema.StringAttribute{
Description: "The cloudlet identifier.",
Computed: true,
},
"flavor": schema.StringAttribute{
Description: "The flavor for the app instance.",
Computed: true,
},
"real_cluster_name": schema.StringAttribute{
Description: "The real cluster name.",
Computed: true,
},
"state": schema.StringAttribute{
Description: "The state of the app instance.",
Computed: true,
},
"runtime_info": schema.StringAttribute{
Description: "Runtime information for the app instance.",
Computed: true,
},
"uri": schema.StringAttribute{
Description: "The URI to access the app instance.",
Computed: true,
},
"liveness": schema.StringAttribute{
Description: "The liveness status of the app instance.",
Computed: true,
},
"power_state": schema.StringAttribute{
Description: "The power state of the app instance.",
Computed: true,
},
"created_at": schema.StringAttribute{
Description: "The timestamp when the app instance was created.",
Computed: true,
},
"updated_at": schema.StringAttribute{
Description: "The timestamp when the app instance was last updated.",
Computed: true,
}, },
}, },
} }
} }
// Configure adds the provider configured client to the data source. func (d *AppInstanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
func (d *appInstDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil { if req.ProviderData == nil {
return return
} }
client, ok := req.ProviderData.(*client.Client) client, ok := req.ProviderData.(*edgeclient.Client)
if !ok { if !ok {
resp.Diagnostics.AddError( resp.Diagnostics.AddError(
"Unexpected Data Source Configure Type", "Unexpected Data Source Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), fmt.Sprintf("Expected *edgeclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
) )
return return
} }
d.client = client d.client = client
} }
// Read refreshes the Terraform state with the latest data. func (d *AppInstanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
func (d *appInstDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var data AppInstanceDataSourceModel
var config appInstDataSourceModel
diags := req.Config.Get(ctx, &config) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Get app instance from API appInstKey := edgeclient.AppInstanceKey{
appInst := client.AppInst{} Organization: "default",
appInst.Key.AppKey.Organization = config.AppOrganization.ValueString() Name: data.Id.ValueString(),
appInst.Key.AppKey.Name = config.AppName.ValueString() CloudletKey: edgeclient.CloudletKey{
appInst.Key.AppKey.Version = config.AppVersion.ValueString() Organization: "default",
appInst.Key.ClusterInstKey.CloudletKey.Organization = config.CloudletOrganization.ValueString() Name: "default-cloudlet",
appInst.Key.ClusterInstKey.CloudletKey.Name = config.CloudletName.ValueString() },
appInst.Key.ClusterInstKey.Organization = config.ClusterOrganization.ValueString() }
readAppInst, err := d.client.GetAppInst(config.Region.ValueString(), appInst) appInstance, err := d.client.ShowAppInstance(ctx, appInstKey, "default")
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app instance %s, got error: %s", data.Id.ValueString(), err))
"Error reading app instance",
"Could not read app instance: "+err.Error(),
)
return return
} }
// Map response to data source model data.Name = types.StringValue(appInstance.Key.Name)
config.ID = types.StringValue(fmt.Sprintf("%s/%s/%s/%s/%s/%s/%s", data.AppId = types.StringValue(appInstance.AppKey.Name)
config.Region.ValueString(), data.Description = types.StringValue("")
config.AppOrganization.ValueString(), data.Config = types.StringValue("")
config.AppName.ValueString(), data.Status = types.StringValue(appInstance.State)
config.AppVersion.ValueString(),
config.CloudletOrganization.ValueString(),
config.CloudletName.ValueString(),
config.ClusterOrganization.ValueString()))
config.Cloudlet = types.StringValue(readAppInst.Cloudlet)
config.Flavor = types.StringValue(readAppInst.Flavor)
config.RealClusterName = types.StringValue(readAppInst.RealClusterName)
config.State = types.StringValue(readAppInst.State)
config.RuntimeInfo = types.StringValue(readAppInst.RuntimeInfo)
config.Uri = types.StringValue(readAppInst.Uri)
config.Liveness = types.StringValue(readAppInst.Liveness)
config.PowerState = types.StringValue(readAppInst.PowerState)
config.CreatedAt = types.StringValue(readAppInst.CreatedAt)
config.UpdatedAt = types.StringValue(readAppInst.UpdatedAt)
diags = resp.State.Set(ctx, &config) tflog.Trace(ctx, "read an app instance data source")
resp.Diagnostics.Append(diags...)
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
} }

View file

@ -4,7 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"github.com/DevFW-CICD/terraform-provider-edge-connect/internal/client"
"github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema"
@ -12,340 +11,238 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
edgeclient "edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/sdk/edgeconnect"
) )
// Ensure the implementation satisfies the expected interfaces. var _ resource.Resource = &AppInstanceResource{}
var ( var _ resource.ResourceWithImportState = &AppInstanceResource{}
_ resource.Resource = &appInstResource{}
_ resource.ResourceWithConfigure = &appInstResource{}
_ resource.ResourceWithImportState = &appInstResource{}
)
// NewAppInstResource is a helper function to simplify the provider implementation. func NewAppInstanceResource() resource.Resource {
func NewAppInstResource() resource.Resource { return &AppInstanceResource{}
return &appInstResource{}
} }
// appInstResource is the resource implementation. type AppInstanceResource struct {
type appInstResource struct { client *edgeclient.Client
client *client.Client
} }
// appInstResourceModel maps the resource schema data. type AppInstanceResourceModel struct {
type appInstResourceModel struct { Id types.String `tfsdk:"id"`
ID types.String `tfsdk:"id"` Name types.String `tfsdk:"name"`
Region types.String `tfsdk:"region"` AppId types.String `tfsdk:"app_id"`
AppOrganization types.String `tfsdk:"app_organization"` Description types.String `tfsdk:"description"`
AppName types.String `tfsdk:"app_name"` Config types.String `tfsdk:"config"`
AppVersion types.String `tfsdk:"app_version"` Status types.String `tfsdk:"status"`
CloudletOrganization types.String `tfsdk:"cloudlet_organization"`
CloudletName types.String `tfsdk:"cloudlet_name"`
ClusterOrganization types.String `tfsdk:"cluster_organization"`
Cloudlet types.String `tfsdk:"cloudlet"`
Flavor types.String `tfsdk:"flavor"`
RealClusterName types.String `tfsdk:"real_cluster_name"`
State types.String `tfsdk:"state"`
RuntimeInfo types.String `tfsdk:"runtime_info"`
Uri types.String `tfsdk:"uri"`
Liveness types.String `tfsdk:"liveness"`
PowerState types.String `tfsdk:"power_state"`
CreatedAt types.String `tfsdk:"created_at"`
UpdatedAt types.String `tfsdk:"updated_at"`
} }
// Metadata returns the resource type name. func (r *AppInstanceResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
func (r *appInstResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_app_instance"
resp.TypeName = req.ProviderTypeName + "_appinst"
} }
// Schema defines the schema for the resource. func (r *AppInstanceResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
func (r *appInstResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{ resp.Schema = schema.Schema{
Description: "Manages an Edge Connect application instance.", MarkdownDescription: "AppInstance resource",
Attributes: map[string]schema.Attribute{ Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{ "id": schema.StringAttribute{
Description: "The unique identifier for the app instance.", Computed: true,
Computed: true, MarkdownDescription: "AppInstance identifier",
PlanModifiers: []planmodifier.String{ PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(), stringplanmodifier.UseStateForUnknown(),
}, },
}, },
"region": schema.StringAttribute{ "name": schema.StringAttribute{
Description: "The region where the app instance is deployed (e.g., 'EU').", MarkdownDescription: "AppInstance name",
Required: true, Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
}, },
"app_organization": schema.StringAttribute{ "app_id": schema.StringAttribute{
Description: "The organization that owns the app.", MarkdownDescription: "Associated App ID",
Required: true, Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
}, },
"app_name": schema.StringAttribute{ "description": schema.StringAttribute{
Description: "The name of the application.", MarkdownDescription: "AppInstance description",
Required: true, Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
}, },
"app_version": schema.StringAttribute{ "config": schema.StringAttribute{
Description: "The version of the application.", MarkdownDescription: "AppInstance configuration",
Required: true, Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
}, },
"cloudlet_organization": schema.StringAttribute{ "status": schema.StringAttribute{
Description: "The organization that owns the cloudlet.", MarkdownDescription: "AppInstance status",
Required: true, Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"cloudlet_name": schema.StringAttribute{
Description: "The name of the cloudlet.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"cluster_organization": schema.StringAttribute{
Description: "The organization that owns the cluster.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"cloudlet": schema.StringAttribute{
Description: "The cloudlet identifier.",
Optional: true,
},
"flavor": schema.StringAttribute{
Description: "The flavor for the app instance (e.g., 'EU.small', 'EU.medium', 'EU.big', 'EU.large').",
Optional: true,
},
"real_cluster_name": schema.StringAttribute{
Description: "The real cluster name.",
Computed: true,
},
"state": schema.StringAttribute{
Description: "The state of the app instance.",
Computed: true,
},
"runtime_info": schema.StringAttribute{
Description: "Runtime information for the app instance.",
Computed: true,
},
"uri": schema.StringAttribute{
Description: "The URI to access the app instance.",
Computed: true,
},
"liveness": schema.StringAttribute{
Description: "The liveness status of the app instance.",
Computed: true,
},
"power_state": schema.StringAttribute{
Description: "The power state of the app instance.",
Computed: true,
},
"created_at": schema.StringAttribute{
Description: "The timestamp when the app instance was created.",
Computed: true,
},
"updated_at": schema.StringAttribute{
Description: "The timestamp when the app instance was last updated.",
Computed: true,
}, },
}, },
} }
} }
// Configure adds the provider configured client to the resource. func (r *AppInstanceResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
func (r *appInstResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil { if req.ProviderData == nil {
return return
} }
client, ok := req.ProviderData.(*client.Client) client, ok := req.ProviderData.(*edgeclient.Client)
if !ok { if !ok {
resp.Diagnostics.AddError( resp.Diagnostics.AddError(
"Unexpected Resource Configure Type", "Unexpected Resource Configure Type",
fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), fmt.Sprintf("Expected *edgeclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
) )
return return
} }
r.client = client r.client = client
} }
// Create creates the resource and sets the initial Terraform state. func (r *AppInstanceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
func (r *appInstResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { var data AppInstanceResourceModel
var plan appInstResourceModel
diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Create new app instance appInstInput := &edgeclient.NewAppInstanceInput{
appInst := client.AppInst{ Region: "default",
Cloudlet: plan.Cloudlet.ValueString(), AppInst: edgeclient.AppInstance{
Flavor: plan.Flavor.ValueString(), Key: edgeclient.AppInstanceKey{
Organization: "default",
Name: data.Name.ValueString(),
CloudletKey: edgeclient.CloudletKey{
Organization: "default",
Name: "default-cloudlet",
},
},
AppKey: edgeclient.AppKey{
Organization: "default",
Name: data.AppId.ValueString(),
Version: "1.0",
},
Flavor: edgeclient.Flavor{Name: "m4.small"},
},
} }
appInst.Key.AppKey.Organization = plan.AppOrganization.ValueString()
appInst.Key.AppKey.Name = plan.AppName.ValueString()
appInst.Key.AppKey.Version = plan.AppVersion.ValueString()
appInst.Key.ClusterInstKey.CloudletKey.Organization = plan.CloudletOrganization.ValueString()
appInst.Key.ClusterInstKey.CloudletKey.Name = plan.CloudletName.ValueString()
appInst.Key.ClusterInstKey.Organization = plan.ClusterOrganization.ValueString()
createdAppInst, err := r.client.CreateAppInst(plan.Region.ValueString(), appInst) err := r.client.CreateAppInstance(ctx, appInstInput)
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create app instance, got error: %s", err))
"Error creating app instance",
"Could not create app instance: "+err.Error(),
)
return return
} }
// Map response body to schema and populate Computed attribute values data.Id = types.StringValue(appInstInput.AppInst.Key.Name)
plan.ID = types.StringValue(fmt.Sprintf("%s/%s/%s/%s/%s/%s/%s", data.Name = types.StringValue(appInstInput.AppInst.Key.Name)
plan.Region.ValueString(), data.AppId = types.StringValue(appInstInput.AppInst.AppKey.Name)
plan.AppOrganization.ValueString(), data.Description = types.StringValue("")
plan.AppName.ValueString(), data.Config = types.StringValue("")
plan.AppVersion.ValueString(), data.Status = types.StringValue("created")
plan.CloudletOrganization.ValueString(),
plan.CloudletName.ValueString(),
plan.ClusterOrganization.ValueString()))
plan.RealClusterName = types.StringValue(createdAppInst.RealClusterName)
plan.State = types.StringValue(createdAppInst.State)
plan.RuntimeInfo = types.StringValue(createdAppInst.RuntimeInfo)
plan.Uri = types.StringValue(createdAppInst.Uri)
plan.Liveness = types.StringValue(createdAppInst.Liveness)
plan.PowerState = types.StringValue(createdAppInst.PowerState)
plan.CreatedAt = types.StringValue(createdAppInst.CreatedAt)
plan.UpdatedAt = types.StringValue(createdAppInst.UpdatedAt)
tflog.Trace(ctx, "created app instance resource") tflog.Trace(ctx, "created an app instance resource")
diags = resp.State.Set(ctx, plan) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
resp.Diagnostics.Append(diags...)
} }
// Read refreshes the Terraform state with the latest data. func (r *AppInstanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
func (r *appInstResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { var data AppInstanceResourceModel
var state appInstResourceModel
diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Get app instance from API appInstKey := edgeclient.AppInstanceKey{
appInst := client.AppInst{} Organization: "default",
appInst.Key.AppKey.Organization = state.AppOrganization.ValueString() Name: data.Id.ValueString(),
appInst.Key.AppKey.Name = state.AppName.ValueString() CloudletKey: edgeclient.CloudletKey{
appInst.Key.AppKey.Version = state.AppVersion.ValueString() Organization: "default",
appInst.Key.ClusterInstKey.CloudletKey.Organization = state.CloudletOrganization.ValueString() Name: "default-cloudlet",
appInst.Key.ClusterInstKey.CloudletKey.Name = state.CloudletName.ValueString() },
appInst.Key.ClusterInstKey.Organization = state.ClusterOrganization.ValueString() }
readAppInst, err := r.client.GetAppInst(state.Region.ValueString(), appInst) appInstance, err := r.client.ShowAppInstance(ctx, appInstKey, "default")
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app instance %s, got error: %s", data.Id.ValueString(), err))
"Error reading app instance",
"Could not read app instance: "+err.Error(),
)
return return
} }
// Map response to state data.Name = types.StringValue(appInstance.Key.Name)
state.Cloudlet = types.StringValue(readAppInst.Cloudlet) data.AppId = types.StringValue(appInstance.AppKey.Name)
state.Flavor = types.StringValue(readAppInst.Flavor) data.Description = types.StringValue("")
state.RealClusterName = types.StringValue(readAppInst.RealClusterName) data.Config = types.StringValue("")
state.State = types.StringValue(readAppInst.State) data.Status = types.StringValue(appInstance.State)
state.RuntimeInfo = types.StringValue(readAppInst.RuntimeInfo)
state.Uri = types.StringValue(readAppInst.Uri)
state.Liveness = types.StringValue(readAppInst.Liveness)
state.PowerState = types.StringValue(readAppInst.PowerState)
state.CreatedAt = types.StringValue(readAppInst.CreatedAt)
state.UpdatedAt = types.StringValue(readAppInst.UpdatedAt)
diags = resp.State.Set(ctx, &state) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
resp.Diagnostics.Append(diags...)
} }
// Update updates the resource and sets the updated Terraform state on success. func (r *AppInstanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
func (r *appInstResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var data AppInstanceResourceModel
var plan appInstResourceModel
diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Update app instance (only limited fields can be updated) updateInput := &edgeclient.UpdateAppInstanceInput{
appInst := client.AppInst{ Region: "default",
Cloudlet: plan.Cloudlet.ValueString(), AppInst: edgeclient.AppInstance{
Flavor: plan.Flavor.ValueString(), Key: edgeclient.AppInstanceKey{
Organization: "default",
Name: data.Name.ValueString(),
CloudletKey: edgeclient.CloudletKey{
Organization: "default",
Name: "default-cloudlet",
},
},
AppKey: edgeclient.AppKey{
Organization: "default",
Name: data.AppId.ValueString(),
Version: "1.0",
},
Flavor: edgeclient.Flavor{Name: "m4.small"},
},
} }
appInst.Key.AppKey.Organization = plan.AppOrganization.ValueString()
appInst.Key.AppKey.Name = plan.AppName.ValueString()
appInst.Key.AppKey.Version = plan.AppVersion.ValueString()
appInst.Key.ClusterInstKey.CloudletKey.Organization = plan.CloudletOrganization.ValueString()
appInst.Key.ClusterInstKey.CloudletKey.Name = plan.CloudletName.ValueString()
appInst.Key.ClusterInstKey.Organization = plan.ClusterOrganization.ValueString()
updatedAppInst, err := r.client.UpdateAppInst(plan.Region.ValueString(), appInst) err := r.client.UpdateAppInstance(ctx, updateInput)
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update app instance, got error: %s", err))
"Error updating app instance",
"Could not update app instance: "+err.Error(),
)
return return
} }
// Update computed attributes data.Name = types.StringValue(updateInput.AppInst.Key.Name)
plan.State = types.StringValue(updatedAppInst.State) data.AppId = types.StringValue(updateInput.AppInst.AppKey.Name)
plan.UpdatedAt = types.StringValue(updatedAppInst.UpdatedAt) data.Description = types.StringValue("")
data.Config = types.StringValue("")
data.Status = types.StringValue("updated")
diags = resp.State.Set(ctx, plan) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
resp.Diagnostics.Append(diags...)
} }
// Delete deletes the resource and removes the Terraform state on success. func (r *AppInstanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
func (r *appInstResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { var data AppInstanceResourceModel
var state appInstResourceModel
diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// Delete app instance appInstKey := edgeclient.AppInstanceKey{
appInst := client.AppInst{} Organization: "default",
appInst.Key.AppKey.Organization = state.AppOrganization.ValueString() Name: data.Id.ValueString(),
appInst.Key.AppKey.Name = state.AppName.ValueString() CloudletKey: edgeclient.CloudletKey{
appInst.Key.AppKey.Version = state.AppVersion.ValueString() Organization: "default",
appInst.Key.ClusterInstKey.CloudletKey.Organization = state.CloudletOrganization.ValueString() Name: "default-cloudlet",
appInst.Key.ClusterInstKey.CloudletKey.Name = state.CloudletName.ValueString() },
appInst.Key.ClusterInstKey.Organization = state.ClusterOrganization.ValueString() }
err := r.client.DeleteAppInst(state.Region.ValueString(), appInst) err := r.client.DeleteAppInstance(ctx, appInstKey, "default")
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete app instance, got error: %s", err))
"Error deleting app instance",
"Could not delete app instance: "+err.Error(),
)
return return
} }
} }
// ImportState imports the resource state. func (r *AppInstanceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
func (r *appInstResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
// Import format: region/app_org/app_name/app_version/cloudlet_org/cloudlet_name/cluster_org
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
} }

View file

@ -2,9 +2,7 @@ package provider
import ( import (
"context" "context"
"os"
"github.com/DevFW-CICD/terraform-provider-edge-connect/internal/client"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/provider"
@ -12,115 +10,67 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
edgeclient "edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/sdk/edgeconnect"
) )
// Ensure the implementation satisfies the expected interfaces. var _ provider.Provider = &EdgeConnectProvider{}
var (
_ provider.Provider = &edgeConnectProvider{}
)
// New is a helper function to simplify provider server and testing implementation. type EdgeConnectProvider struct {
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &edgeConnectProvider{
version: version,
}
}
}
// edgeConnectProvider is the provider implementation.
type edgeConnectProvider struct {
version string version string
} }
// edgeConnectProviderModel maps provider schema data to a Go type. type EdgeConnectProviderModel struct {
type edgeConnectProviderModel struct { Endpoint types.String `tfsdk:"endpoint"`
BaseURL types.String `tfsdk:"base_url"`
Token types.String `tfsdk:"token"` Token types.String `tfsdk:"token"`
Username types.String `tfsdk:"username"`
Password types.String `tfsdk:"password"`
} }
// Metadata returns the provider type name. func (p *EdgeConnectProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) {
func (p *edgeConnectProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "edge-connect" resp.TypeName = "edge-connect"
resp.Version = p.version resp.Version = p.version
} }
// Schema defines the provider-level schema for configuration data. func (p *EdgeConnectProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) {
func (p *edgeConnectProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{ resp.Schema = schema.Schema{
Description: "Interact with Edge Connect API for managing applications and application instances.",
Attributes: map[string]schema.Attribute{ Attributes: map[string]schema.Attribute{
"base_url": schema.StringAttribute{ "endpoint": schema.StringAttribute{
Description: "The base URL for the Edge Connect API. May also be provided via EDGE_CONNECT_BASE_URL environment variable.", MarkdownDescription: "Edge Connect API endpoint",
Optional: true, Required: true,
}, },
"token": schema.StringAttribute{ "token": schema.StringAttribute{
Description: "Bearer token for authentication. May also be provided via EDGE_CONNECT_TOKEN environment variable.", MarkdownDescription: "Edge Connect API token",
Optional: true, Required: true,
Sensitive: true, Sensitive: true,
},
"username": schema.StringAttribute{
Description: "Username for basic authentication. May also be provided via EDGE_CONNECT_USERNAME environment variable.",
Optional: true,
},
"password": schema.StringAttribute{
Description: "Password for basic authentication. May also be provided via EDGE_CONNECT_PASSWORD environment variable.",
Optional: true,
Sensitive: true,
}, },
}, },
} }
} }
// Configure prepares a Edge Connect API client for data sources and resources. func (p *EdgeConnectProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
func (p *edgeConnectProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { var data EdgeConnectProviderModel
tflog.Info(ctx, "Configuring Edge Connect client")
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
// Retrieve provider data from configuration
var config edgeConnectProviderModel
diags := req.Config.Get(ctx, &config)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
} }
// If practitioner provided a configuration value for any of the endpoint := data.Endpoint.ValueString()
// attributes, it must be a known value. token := data.Token.ValueString()
if config.BaseURL.IsUnknown() {
if endpoint == "" {
resp.Diagnostics.AddAttributeError( resp.Diagnostics.AddAttributeError(
path.Root("base_url"), path.Root("endpoint"),
"Unknown Edge Connect API Base URL", "Missing Edge Connect API Endpoint",
"The provider cannot create the Edge Connect API client as there is an unknown configuration value for the base URL. "+ "The provider cannot create the Edge Connect API client as there is a missing or empty value for the Edge Connect API endpoint.",
"Either target apply the source of the value first, set the value statically in the configuration, or use the EDGE_CONNECT_BASE_URL environment variable.",
) )
} }
if config.Token.IsUnknown() { if token == "" {
resp.Diagnostics.AddAttributeError( resp.Diagnostics.AddAttributeError(
path.Root("token"), path.Root("token"),
"Unknown Edge Connect API Token", "Missing Edge Connect API Token",
"The provider cannot create the Edge Connect API client as there is an unknown configuration value for the token. "+ "The provider cannot create the Edge Connect API client as there is a missing or empty value for the Edge Connect API token.",
"Either target apply the source of the value first, set the value statically in the configuration, or use the EDGE_CONNECT_TOKEN environment variable.",
)
}
if config.Username.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("username"),
"Unknown Edge Connect API Username",
"The provider cannot create the Edge Connect API client as there is an unknown configuration value for the username. "+
"Either target apply the source of the value first, set the value statically in the configuration, or use the EDGE_CONNECT_USERNAME environment variable.",
)
}
if config.Password.IsUnknown() {
resp.Diagnostics.AddAttributeError(
path.Root("password"),
"Unknown Edge Connect API Password",
"The provider cannot create the Edge Connect API client as there is an unknown configuration value for the password. "+
"Either target apply the source of the value first, set the value statically in the configuration, or use the EDGE_CONNECT_PASSWORD environment variable.",
) )
} }
@ -128,97 +78,37 @@ func (p *edgeConnectProvider) Configure(ctx context.Context, req provider.Config
return return
} }
// Default values to environment variables, but override ctx = tflog.SetField(ctx, "edge_connect_endpoint", endpoint)
// with Terraform configuration value if set.
baseURL := os.Getenv("EDGE_CONNECT_BASE_URL")
token := os.Getenv("EDGE_CONNECT_TOKEN")
username := os.Getenv("EDGE_CONNECT_USERNAME")
password := os.Getenv("EDGE_CONNECT_PASSWORD")
if !config.BaseURL.IsNull() {
baseURL = config.BaseURL.ValueString()
}
if !config.Token.IsNull() {
token = config.Token.ValueString()
}
if !config.Username.IsNull() {
username = config.Username.ValueString()
}
if !config.Password.IsNull() {
password = config.Password.ValueString()
}
// If any of the expected configurations are missing, return
// errors with provider-specific guidance.
if baseURL == "" {
resp.Diagnostics.AddAttributeError(
path.Root("base_url"),
"Missing Edge Connect API Base URL",
"The provider requires a base URL for the Edge Connect API. "+
"Set the base_url value in the configuration or use the EDGE_CONNECT_BASE_URL environment variable. "+
"If either is already set, ensure the value is not empty.",
)
}
if token == "" && (username == "" || password == "") {
resp.Diagnostics.AddError(
"Missing Edge Connect API Authentication",
"The provider requires either a bearer token or username/password for authentication. "+
"Set the token value in the configuration or use the EDGE_CONNECT_TOKEN environment variable, "+
"or set username and password values in the configuration or use the EDGE_CONNECT_USERNAME and EDGE_CONNECT_PASSWORD environment variables.",
)
}
if resp.Diagnostics.HasError() {
return
}
ctx = tflog.SetField(ctx, "edge_connect_base_url", baseURL)
ctx = tflog.SetField(ctx, "edge_connect_token", token)
ctx = tflog.SetField(ctx, "edge_connect_username", username)
ctx = tflog.SetField(ctx, "edge_connect_password", password)
ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "edge_connect_token") ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "edge_connect_token")
ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "edge_connect_password")
tflog.Debug(ctx, "Creating Edge Connect client") tflog.Debug(ctx, "Creating Edge Connect client")
// Create a new Edge Connect client using the configuration values client := edgeclient.NewClient(endpoint)
apiClient := client.NewClient(baseURL, token, username, password)
// Test the connection resp.DataSourceData = client
if err := apiClient.HealthCheck(); err != nil { resp.ResourceData = client
resp.Diagnostics.AddError(
"Unable to Connect to Edge Connect API",
"An error occurred while connecting to the Edge Connect API. "+
"Please verify that your base URL and authentication credentials are correct.\n\n"+
"Edge Connect Client Error: "+err.Error(),
)
return
}
// Make the Edge Connect client available during DataSource and Resource
// type Configure methods.
resp.DataSourceData = apiClient
resp.ResourceData = apiClient
tflog.Info(ctx, "Configured Edge Connect client", map[string]any{"success": true}) tflog.Info(ctx, "Configured Edge Connect client", map[string]any{"success": true})
} }
// DataSources defines the data sources implemented in the provider. func (p *EdgeConnectProvider) Resources(ctx context.Context) []func() resource.Resource {
func (p *edgeConnectProvider) DataSources(_ context.Context) []func() datasource.DataSource { return []func() resource.Resource{
return []func() datasource.DataSource{ NewAppResource,
NewAppDataSource, NewAppInstanceResource,
NewAppInstDataSource,
} }
} }
// Resources defines the resources implemented in the provider. func (p *EdgeConnectProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
func (p *edgeConnectProvider) Resources(_ context.Context) []func() resource.Resource { return []func() datasource.DataSource{
return []func() resource.Resource{ NewAppDataSource,
NewAppResource, NewAppInstanceDataSource,
NewAppInstResource, }
}
func New(version string) func() provider.Provider {
return func() provider.Provider {
return &EdgeConnectProvider{
version: version,
}
} }
} }