From a88de9f2e8af9435ddf254103b856e5811ff9b2b Mon Sep 17 00:00:00 2001 From: Manuel Ganter Date: Tue, 11 Nov 2025 15:25:57 +0100 Subject: [PATCH] now using client sdk --- go.mod | 21 +- go.sum | 59 +++- internal/client/app.go | 105 ------ internal/client/appinst.go | 114 ------- internal/client/client.go | 81 ----- internal/client/models.go | 82 ----- internal/provider/app_data_source.go | 171 ++++------ internal/provider/app_resource.go | 319 +++++++------------ internal/provider/appinst_data_source.go | 211 ++++-------- internal/provider/appinst_resource.go | 389 +++++++++-------------- internal/provider/provider.go | 206 +++--------- 11 files changed, 497 insertions(+), 1261 deletions(-) delete mode 100644 internal/client/app.go delete mode 100644 internal/client/appinst.go delete mode 100644 internal/client/client.go delete mode 100644 internal/client/models.go diff --git a/go.mod b/go.mod index 8275fcf..46879f2 100644 --- a/go.mod +++ b/go.mod @@ -3,30 +3,47 @@ module github.com/DevFW-CICD/terraform-provider-edge-connect go 1.25.3 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-log v0.9.0 ) 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/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-hclog v1.6.3 // 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/terraform-plugin-go v0.29.0 // indirect github.com/hashicorp/terraform-registry-address v0.4.0 // indirect github.com/hashicorp/terraform-svchost v0.1.1 // 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-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/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/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/sys v0.35.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/grpc v1.75.1 // indirect google.golang.org/protobuf v1.36.9 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 1b5a0b6..7b34213 100644 --- a/go.sum +++ b/go.sum @@ -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/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.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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/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/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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-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/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 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/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/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/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 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/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= 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/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.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 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.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.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +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/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= 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/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.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 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.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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +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/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= 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/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= 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/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= 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/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= 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/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/client/app.go b/internal/client/app.go deleted file mode 100644 index 55128b3..0000000 --- a/internal/client/app.go +++ /dev/null @@ -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 -} diff --git a/internal/client/appinst.go b/internal/client/appinst.go deleted file mode 100644 index c335c79..0000000 --- a/internal/client/appinst.go +++ /dev/null @@ -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 -} diff --git a/internal/client/client.go b/internal/client/client.go deleted file mode 100644 index 6c425eb..0000000 --- a/internal/client/client.go +++ /dev/null @@ -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 -} diff --git a/internal/client/models.go b/internal/client/models.go deleted file mode 100644 index ac639a6..0000000 --- a/internal/client/models.go +++ /dev/null @@ -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"` -} diff --git a/internal/provider/app_data_source.go b/internal/provider/app_data_source.go index e676978..14476bb 100644 --- a/internal/provider/app_data_source.go +++ b/internal/provider/app_data_source.go @@ -4,174 +4,111 @@ import ( "context" "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/schema" "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{} - _ datasource.DataSourceWithConfigure = &appDataSource{} -) +var _ datasource.DataSource = &AppDataSource{} -// NewAppDataSource is a helper function to simplify the provider implementation. func NewAppDataSource() datasource.DataSource { - return &appDataSource{} + return &AppDataSource{} } -// appDataSource is the data source implementation. -type appDataSource struct { - client *client.Client +type AppDataSource struct { + client *edgeclient.Client } -// appDataSourceModel maps the data source schema data. -type appDataSourceModel struct { - ID types.String `tfsdk:"id"` - Region types.String `tfsdk:"region"` - Organization types.String `tfsdk:"organization"` - Name types.String `tfsdk:"name"` - 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"` +type AppDataSourceModel struct { + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Version types.String `tfsdk:"version"` + Status types.String `tfsdk:"status"` } -// Metadata returns the data source type name. -func (d *appDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { +func (d *AppDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_app" } -// Schema defines the schema for the data source. -func (d *appDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { +func (d *AppDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ - Description: "Fetches an Edge Connect application specification.", + MarkdownDescription: "App data source", + Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - Description: "The unique identifier for the app (format: region/organization/name/version).", - Computed: 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, + MarkdownDescription: "App identifier", + Required: true, }, "name": schema.StringAttribute{ - Description: "The name of the application.", - Required: true, + MarkdownDescription: "App name", + Computed: true, + }, + "description": schema.StringAttribute{ + MarkdownDescription: "App description", + Computed: true, }, "version": schema.StringAttribute{ - Description: "The version of the application.", - Required: true, + MarkdownDescription: "App version", + Computed: true, }, - "image_type": schema.StringAttribute{ - Description: "The type of image (e.g., 'Docker').", - 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, + "status": schema.StringAttribute{ + MarkdownDescription: "App status", + Computed: true, }, }, } } -// Configure adds the provider configured client to the data source. -func (d *appDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { +func (d *AppDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { if req.ProviderData == nil { return } - client, ok := req.ProviderData.(*client.Client) + client, ok := req.ProviderData.(*edgeclient.Client) + if !ok { resp.Diagnostics.AddError( "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 } 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) { - var config appDataSourceModel - diags := req.Config.Get(ctx, &config) - resp.Diagnostics.Append(diags...) +func (d *AppDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data AppDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Get app from API - app := client.App{} - app.Key.Organization = config.Organization.ValueString() - app.Key.Name = config.Name.ValueString() - app.Key.Version = config.Version.ValueString() + appKey := edgeclient.AppKey{ + Organization: "default", + Name: data.Id.ValueString(), + Version: "", + } - readApp, err := d.client.GetApp(config.Region.ValueString(), app) + app, err := d.client.ShowApp(ctx, appKey, "default") if err != nil { - resp.Diagnostics.AddError( - "Error reading app", - "Could not read app: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app %s, got error: %s", data.Id.ValueString(), err)) return } - // Map response to data source model - config.ID = types.StringValue(fmt.Sprintf("%s/%s/%s/%s", - config.Region.ValueString(), - readApp.Key.Organization, - 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) + data.Name = types.StringValue(app.Key.Name) + data.Description = types.StringValue("") + data.Version = types.StringValue(app.Key.Version) + data.Status = types.StringValue("") - diags = resp.State.Set(ctx, &config) - resp.Diagnostics.Append(diags...) + tflog.Trace(ctx, "read an app data source") + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } diff --git a/internal/provider/app_resource.go b/internal/provider/app_resource.go index cbaa286..ac94630 100644 --- a/internal/provider/app_resource.go +++ b/internal/provider/app_resource.go @@ -4,7 +4,6 @@ import ( "context" "fmt" - "github.com/DevFW-CICD/terraform-provider-edge-connect/internal/client" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "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/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 ( - _ resource.Resource = &appResource{} - _ resource.ResourceWithConfigure = &appResource{} - _ resource.ResourceWithImportState = &appResource{} -) +var _ resource.Resource = &AppResource{} +var _ resource.ResourceWithImportState = &AppResource{} -// NewAppResource is a helper function to simplify the provider implementation. func NewAppResource() resource.Resource { - return &appResource{} + return &AppResource{} } -// appResource is the resource implementation. -type appResource struct { - client *client.Client +type AppResource struct { + client *edgeclient.Client } -// appResourceModel maps the resource schema data. -type appResourceModel struct { - ID types.String `tfsdk:"id"` - Region types.String `tfsdk:"region"` - Organization types.String `tfsdk:"organization"` - Name types.String `tfsdk:"name"` - 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"` +type AppResourceModel struct { + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Version types.String `tfsdk:"version"` + Status types.String `tfsdk:"status"` } -// Metadata returns the resource type name. -func (r *appResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *AppResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_app" } -// Schema defines the schema for the resource. -func (r *appResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *AppResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ - Description: "Manages an Edge Connect application specification.", + MarkdownDescription: "App resource", + Attributes: map[string]schema.Attribute{ "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{ 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{ - Description: "The name of the application.", - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, + MarkdownDescription: "App name", + Required: true, + }, + "description": schema.StringAttribute{ + MarkdownDescription: "App description", + Optional: true, }, "version": schema.StringAttribute{ - Description: "The version of the application.", - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, + MarkdownDescription: "App version", + Optional: true, }, - "image_type": schema.StringAttribute{ - Description: "The type of image (e.g., 'Docker').", - Required: 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, + "status": schema.StringAttribute{ + MarkdownDescription: "App status", + Computed: true, }, }, } } -// Configure adds the provider configured client to the resource. -func (r *appResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *AppResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { if req.ProviderData == nil { return } - client, ok := req.ProviderData.(*client.Client) + client, ok := req.ProviderData.(*edgeclient.Client) + if !ok { resp.Diagnostics.AddError( "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 } 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) { - var plan appResourceModel - diags := req.Plan.Get(ctx, &plan) - resp.Diagnostics.Append(diags...) +func (r *AppResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data AppResourceModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Create new app - app := client.App{ - Region: plan.Region.ValueString(), - ImageType: plan.ImageType.ValueString(), - ImagePath: plan.ImagePath.ValueString(), - DefaultFlavor: plan.DefaultFlavor.ValueString(), - Deployment: plan.Deployment.ValueString(), - DeploymentManifest: plan.DeploymentManifest.ValueString(), - AccessPorts: plan.AccessPorts.ValueString(), - Annotations: plan.Annotations.ValueString(), + appInput := &edgeclient.NewAppInput{ + Region: "default", + App: edgeclient.App{ + Key: edgeclient.AppKey{ + Organization: "default", + Name: data.Name.ValueString(), + Version: data.Version.ValueString(), + }, + Deployment: "kubernetes", + 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 { - resp.Diagnostics.AddError( - "Error creating app", - "Could not create app: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create app, got error: %s", err)) return } - // Map response body to schema and populate Computed attribute values - plan.ID = types.StringValue(fmt.Sprintf("%s/%s/%s/%s", - plan.Region.ValueString(), - createdApp.Key.Organization, - createdApp.Key.Name, - createdApp.Key.Version)) - plan.CreatedAt = types.StringValue(createdApp.CreatedAt) - plan.UpdatedAt = types.StringValue(createdApp.UpdatedAt) + data.Id = types.StringValue(appInput.App.Key.Name) + data.Name = types.StringValue(appInput.App.Key.Name) + data.Description = types.StringValue("") + data.Version = types.StringValue(appInput.App.Key.Version) + data.Status = types.StringValue("created") - tflog.Trace(ctx, "created app resource") + tflog.Trace(ctx, "created an app resource") - diags = resp.State.Set(ctx, plan) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -// Read refreshes the Terraform state with the latest data. -func (r *appResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var state appResourceModel - diags := req.State.Get(ctx, &state) - resp.Diagnostics.Append(diags...) +func (r *AppResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data AppResourceModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Get app from API - app := client.App{} - app.Key.Organization = state.Organization.ValueString() - app.Key.Name = state.Name.ValueString() - app.Key.Version = state.Version.ValueString() + appKey := edgeclient.AppKey{ + Organization: "default", + Name: data.Id.ValueString(), + Version: data.Version.ValueString(), + } - readApp, err := r.client.GetApp(state.Region.ValueString(), app) + app, err := r.client.ShowApp(ctx, appKey, "default") if err != nil { - resp.Diagnostics.AddError( - "Error reading app", - "Could not read app: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app %s, got error: %s", data.Id.ValueString(), err)) return } - // Map response to state - state.ImageType = types.StringValue(readApp.ImageType) - state.ImagePath = types.StringValue(readApp.ImagePath) - state.DefaultFlavor = types.StringValue(readApp.DefaultFlavor) - 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) + data.Name = types.StringValue(app.Key.Name) + data.Description = types.StringValue("") + data.Version = types.StringValue(app.Key.Version) + data.Status = types.StringValue("") - diags = resp.State.Set(ctx, &state) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -// 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) { - var plan appResourceModel - diags := req.Plan.Get(ctx, &plan) - resp.Diagnostics.Append(diags...) +func (r *AppResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data AppResourceModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Update app - app := client.App{ - Region: plan.Region.ValueString(), - ImageType: plan.ImageType.ValueString(), - ImagePath: plan.ImagePath.ValueString(), - DefaultFlavor: plan.DefaultFlavor.ValueString(), - Deployment: plan.Deployment.ValueString(), - DeploymentManifest: plan.DeploymentManifest.ValueString(), - AccessPorts: plan.AccessPorts.ValueString(), - Annotations: plan.Annotations.ValueString(), + updateInput := &edgeclient.UpdateAppInput{ + Region: "default", + App: edgeclient.App{ + Key: edgeclient.AppKey{ + Organization: "default", + Name: data.Name.ValueString(), + Version: data.Version.ValueString(), + }, + Deployment: "kubernetes", + 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 { - resp.Diagnostics.AddError( - "Error updating app", - "Could not update app: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update app, got error: %s", err)) return } - // Update computed attributes - plan.UpdatedAt = types.StringValue(updatedApp.UpdatedAt) + data.Name = types.StringValue(updateInput.App.Key.Name) + 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(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -// Delete deletes the resource and removes the Terraform state on success. -func (r *appResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var state appResourceModel - diags := req.State.Get(ctx, &state) - resp.Diagnostics.Append(diags...) +func (r *AppResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data AppResourceModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Delete app - app := client.App{} - app.Key.Organization = state.Organization.ValueString() - app.Key.Name = state.Name.ValueString() - app.Key.Version = state.Version.ValueString() + appKey := edgeclient.AppKey{ + Organization: "default", + Name: data.Id.ValueString(), + Version: data.Version.ValueString(), + } - err := r.client.DeleteApp(state.Region.ValueString(), app) + err := r.client.DeleteApp(ctx, appKey, "default") if err != nil { - resp.Diagnostics.AddError( - "Error deleting app", - "Could not delete app: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete app, got error: %s", err)) return } } -// ImportState imports the resource state. -func (r *appResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - // Import format: region/organization/name/version +func (r *AppResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } diff --git a/internal/provider/appinst_data_source.go b/internal/provider/appinst_data_source.go index c0f090f..1264c24 100644 --- a/internal/provider/appinst_data_source.go +++ b/internal/provider/appinst_data_source.go @@ -4,201 +4,120 @@ import ( "context" "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/schema" "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 = &appInstDataSource{} - _ datasource.DataSourceWithConfigure = &appInstDataSource{} -) +var _ datasource.DataSource = &AppInstanceDataSource{} -// NewAppInstDataSource is a helper function to simplify the provider implementation. -func NewAppInstDataSource() datasource.DataSource { - return &appInstDataSource{} +func NewAppInstanceDataSource() datasource.DataSource { + return &AppInstanceDataSource{} } -// appInstDataSource is the data source implementation. -type appInstDataSource struct { - client *client.Client +type AppInstanceDataSource struct { + client *edgeclient.Client } -// appInstDataSourceModel maps the data source schema data. -type appInstDataSourceModel struct { - ID types.String `tfsdk:"id"` - Region types.String `tfsdk:"region"` - AppOrganization types.String `tfsdk:"app_organization"` - AppName types.String `tfsdk:"app_name"` - AppVersion types.String `tfsdk:"app_version"` - 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"` +type AppInstanceDataSourceModel struct { + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + AppId types.String `tfsdk:"app_id"` + Description types.String `tfsdk:"description"` + Config types.String `tfsdk:"config"` + Status types.String `tfsdk:"status"` } -// Metadata returns the data source type name. -func (d *appInstDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_appinst" +func (d *AppInstanceDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_app_instance" } -// Schema defines the schema for the data source. -func (d *appInstDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { +func (d *AppInstanceDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ - Description: "Fetches an Edge Connect application instance.", + MarkdownDescription: "AppInstance data source", + Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - Description: "The unique identifier for the app instance.", - Computed: true, + MarkdownDescription: "AppInstance identifier", + Required: true, }, - "region": schema.StringAttribute{ - Description: "The region where the app instance is deployed (e.g., 'EU').", - Required: true, + "name": schema.StringAttribute{ + MarkdownDescription: "AppInstance name", + Computed: true, }, - "app_organization": schema.StringAttribute{ - Description: "The organization that owns the app.", - Required: true, + "app_id": schema.StringAttribute{ + MarkdownDescription: "Associated App ID", + Computed: true, }, - "app_name": schema.StringAttribute{ - Description: "The name of the application.", - Required: true, + "description": schema.StringAttribute{ + MarkdownDescription: "AppInstance description", + Computed: true, }, - "app_version": schema.StringAttribute{ - Description: "The version of the application.", - Required: true, + "config": schema.StringAttribute{ + MarkdownDescription: "AppInstance configuration", + Computed: true, }, - "cloudlet_organization": schema.StringAttribute{ - Description: "The organization that owns the cloudlet.", - Required: 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, + "status": schema.StringAttribute{ + MarkdownDescription: "AppInstance status", + Computed: true, }, }, } } -// Configure adds the provider configured client to the data source. -func (d *appInstDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { +func (d *AppInstanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { if req.ProviderData == nil { return } - client, ok := req.ProviderData.(*client.Client) + client, ok := req.ProviderData.(*edgeclient.Client) + if !ok { resp.Diagnostics.AddError( "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 } d.client = client } -// Read refreshes the Terraform state with the latest data. -func (d *appInstDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var config appInstDataSourceModel - diags := req.Config.Get(ctx, &config) - resp.Diagnostics.Append(diags...) +func (d *AppInstanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var data AppInstanceDataSourceModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Get app instance from API - appInst := client.AppInst{} - appInst.Key.AppKey.Organization = config.AppOrganization.ValueString() - appInst.Key.AppKey.Name = config.AppName.ValueString() - appInst.Key.AppKey.Version = config.AppVersion.ValueString() - appInst.Key.ClusterInstKey.CloudletKey.Organization = config.CloudletOrganization.ValueString() - appInst.Key.ClusterInstKey.CloudletKey.Name = config.CloudletName.ValueString() - appInst.Key.ClusterInstKey.Organization = config.ClusterOrganization.ValueString() + appInstKey := edgeclient.AppInstanceKey{ + Organization: "default", + Name: data.Id.ValueString(), + CloudletKey: edgeclient.CloudletKey{ + Organization: "default", + Name: "default-cloudlet", + }, + } - readAppInst, err := d.client.GetAppInst(config.Region.ValueString(), appInst) + appInstance, err := d.client.ShowAppInstance(ctx, appInstKey, "default") if err != nil { - resp.Diagnostics.AddError( - "Error reading app instance", - "Could not read app instance: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app instance %s, got error: %s", data.Id.ValueString(), err)) return } - // Map response to data source model - config.ID = types.StringValue(fmt.Sprintf("%s/%s/%s/%s/%s/%s/%s", - config.Region.ValueString(), - config.AppOrganization.ValueString(), - config.AppName.ValueString(), - 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) + data.Name = types.StringValue(appInstance.Key.Name) + data.AppId = types.StringValue(appInstance.AppKey.Name) + data.Description = types.StringValue("") + data.Config = types.StringValue("") + data.Status = types.StringValue(appInstance.State) - diags = resp.State.Set(ctx, &config) - resp.Diagnostics.Append(diags...) + tflog.Trace(ctx, "read an app instance data source") + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } diff --git a/internal/provider/appinst_resource.go b/internal/provider/appinst_resource.go index c8a08fb..163ce09 100644 --- a/internal/provider/appinst_resource.go +++ b/internal/provider/appinst_resource.go @@ -4,7 +4,6 @@ import ( "context" "fmt" - "github.com/DevFW-CICD/terraform-provider-edge-connect/internal/client" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "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/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 ( - _ resource.Resource = &appInstResource{} - _ resource.ResourceWithConfigure = &appInstResource{} - _ resource.ResourceWithImportState = &appInstResource{} -) +var _ resource.Resource = &AppInstanceResource{} +var _ resource.ResourceWithImportState = &AppInstanceResource{} -// NewAppInstResource is a helper function to simplify the provider implementation. -func NewAppInstResource() resource.Resource { - return &appInstResource{} +func NewAppInstanceResource() resource.Resource { + return &AppInstanceResource{} } -// appInstResource is the resource implementation. -type appInstResource struct { - client *client.Client +type AppInstanceResource struct { + client *edgeclient.Client } -// appInstResourceModel maps the resource schema data. -type appInstResourceModel struct { - ID types.String `tfsdk:"id"` - Region types.String `tfsdk:"region"` - AppOrganization types.String `tfsdk:"app_organization"` - AppName types.String `tfsdk:"app_name"` - AppVersion types.String `tfsdk:"app_version"` - 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"` +type AppInstanceResourceModel struct { + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + AppId types.String `tfsdk:"app_id"` + Description types.String `tfsdk:"description"` + Config types.String `tfsdk:"config"` + Status types.String `tfsdk:"status"` } -// Metadata returns the resource type name. -func (r *appInstResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_appinst" +func (r *AppInstanceResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_app_instance" } -// Schema defines the schema for the resource. -func (r *appInstResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *AppInstanceResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ - Description: "Manages an Edge Connect application instance.", + MarkdownDescription: "AppInstance resource", + Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - Description: "The unique identifier for the app instance.", - Computed: true, + Computed: true, + MarkdownDescription: "AppInstance identifier", PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, - "region": schema.StringAttribute{ - Description: "The region where the app instance is deployed (e.g., 'EU').", - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, + "name": schema.StringAttribute{ + MarkdownDescription: "AppInstance name", + Required: true, }, - "app_organization": schema.StringAttribute{ - Description: "The organization that owns the app.", - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, + "app_id": schema.StringAttribute{ + MarkdownDescription: "Associated App ID", + Required: true, }, - "app_name": schema.StringAttribute{ - Description: "The name of the application.", - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, + "description": schema.StringAttribute{ + MarkdownDescription: "AppInstance description", + Optional: true, }, - "app_version": schema.StringAttribute{ - Description: "The version of the application.", - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, + "config": schema.StringAttribute{ + MarkdownDescription: "AppInstance configuration", + Optional: true, }, - "cloudlet_organization": schema.StringAttribute{ - Description: "The organization that owns the cloudlet.", - Required: 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, + "status": schema.StringAttribute{ + MarkdownDescription: "AppInstance status", + Computed: true, }, }, } } -// Configure adds the provider configured client to the resource. -func (r *appInstResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *AppInstanceResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { if req.ProviderData == nil { return } - client, ok := req.ProviderData.(*client.Client) + client, ok := req.ProviderData.(*edgeclient.Client) + if !ok { resp.Diagnostics.AddError( "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 } r.client = client } -// Create creates the resource and sets the initial Terraform state. -func (r *appInstResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var plan appInstResourceModel - diags := req.Plan.Get(ctx, &plan) - resp.Diagnostics.Append(diags...) +func (r *AppInstanceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data AppInstanceResourceModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Create new app instance - appInst := client.AppInst{ - Cloudlet: plan.Cloudlet.ValueString(), - Flavor: plan.Flavor.ValueString(), + appInstInput := &edgeclient.NewAppInstanceInput{ + Region: "default", + AppInst: edgeclient.AppInstance{ + 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 { - resp.Diagnostics.AddError( - "Error creating app instance", - "Could not create app instance: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create app instance, got error: %s", err)) return } - // Map response body to schema and populate Computed attribute values - plan.ID = types.StringValue(fmt.Sprintf("%s/%s/%s/%s/%s/%s/%s", - plan.Region.ValueString(), - plan.AppOrganization.ValueString(), - plan.AppName.ValueString(), - plan.AppVersion.ValueString(), - 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) + data.Id = types.StringValue(appInstInput.AppInst.Key.Name) + data.Name = types.StringValue(appInstInput.AppInst.Key.Name) + data.AppId = types.StringValue(appInstInput.AppInst.AppKey.Name) + data.Description = types.StringValue("") + data.Config = types.StringValue("") + data.Status = types.StringValue("created") - tflog.Trace(ctx, "created app instance resource") + tflog.Trace(ctx, "created an app instance resource") - diags = resp.State.Set(ctx, plan) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -// Read refreshes the Terraform state with the latest data. -func (r *appInstResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var state appInstResourceModel - diags := req.State.Get(ctx, &state) - resp.Diagnostics.Append(diags...) +func (r *AppInstanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data AppInstanceResourceModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Get app instance from API - appInst := client.AppInst{} - appInst.Key.AppKey.Organization = state.AppOrganization.ValueString() - appInst.Key.AppKey.Name = state.AppName.ValueString() - appInst.Key.AppKey.Version = state.AppVersion.ValueString() - appInst.Key.ClusterInstKey.CloudletKey.Organization = state.CloudletOrganization.ValueString() - appInst.Key.ClusterInstKey.CloudletKey.Name = state.CloudletName.ValueString() - appInst.Key.ClusterInstKey.Organization = state.ClusterOrganization.ValueString() + appInstKey := edgeclient.AppInstanceKey{ + Organization: "default", + Name: data.Id.ValueString(), + CloudletKey: edgeclient.CloudletKey{ + Organization: "default", + Name: "default-cloudlet", + }, + } - readAppInst, err := r.client.GetAppInst(state.Region.ValueString(), appInst) + appInstance, err := r.client.ShowAppInstance(ctx, appInstKey, "default") if err != nil { - resp.Diagnostics.AddError( - "Error reading app instance", - "Could not read app instance: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app instance %s, got error: %s", data.Id.ValueString(), err)) return } - // Map response to state - state.Cloudlet = types.StringValue(readAppInst.Cloudlet) - state.Flavor = types.StringValue(readAppInst.Flavor) - state.RealClusterName = types.StringValue(readAppInst.RealClusterName) - state.State = types.StringValue(readAppInst.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) + data.Name = types.StringValue(appInstance.Key.Name) + data.AppId = types.StringValue(appInstance.AppKey.Name) + data.Description = types.StringValue("") + data.Config = types.StringValue("") + data.Status = types.StringValue(appInstance.State) - diags = resp.State.Set(ctx, &state) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -// Update updates the resource and sets the updated Terraform state on success. -func (r *appInstResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var plan appInstResourceModel - diags := req.Plan.Get(ctx, &plan) - resp.Diagnostics.Append(diags...) +func (r *AppInstanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data AppInstanceResourceModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Update app instance (only limited fields can be updated) - appInst := client.AppInst{ - Cloudlet: plan.Cloudlet.ValueString(), - Flavor: plan.Flavor.ValueString(), + updateInput := &edgeclient.UpdateAppInstanceInput{ + Region: "default", + AppInst: edgeclient.AppInstance{ + 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 { - resp.Diagnostics.AddError( - "Error updating app instance", - "Could not update app instance: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update app instance, got error: %s", err)) return } - // Update computed attributes - plan.State = types.StringValue(updatedAppInst.State) - plan.UpdatedAt = types.StringValue(updatedAppInst.UpdatedAt) + data.Name = types.StringValue(updateInput.AppInst.Key.Name) + data.AppId = types.StringValue(updateInput.AppInst.AppKey.Name) + data.Description = types.StringValue("") + data.Config = types.StringValue("") + data.Status = types.StringValue("updated") - diags = resp.State.Set(ctx, plan) - resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } -// Delete deletes the resource and removes the Terraform state on success. -func (r *appInstResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var state appInstResourceModel - diags := req.State.Get(ctx, &state) - resp.Diagnostics.Append(diags...) +func (r *AppInstanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data AppInstanceResourceModel + + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { return } - // Delete app instance - appInst := client.AppInst{} - appInst.Key.AppKey.Organization = state.AppOrganization.ValueString() - appInst.Key.AppKey.Name = state.AppName.ValueString() - appInst.Key.AppKey.Version = state.AppVersion.ValueString() - appInst.Key.ClusterInstKey.CloudletKey.Organization = state.CloudletOrganization.ValueString() - appInst.Key.ClusterInstKey.CloudletKey.Name = state.CloudletName.ValueString() - appInst.Key.ClusterInstKey.Organization = state.ClusterOrganization.ValueString() + appInstKey := edgeclient.AppInstanceKey{ + Organization: "default", + Name: data.Id.ValueString(), + CloudletKey: edgeclient.CloudletKey{ + Organization: "default", + Name: "default-cloudlet", + }, + } - err := r.client.DeleteAppInst(state.Region.ValueString(), appInst) + err := r.client.DeleteAppInstance(ctx, appInstKey, "default") if err != nil { - resp.Diagnostics.AddError( - "Error deleting app instance", - "Could not delete app instance: "+err.Error(), - ) + resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete app instance, got error: %s", err)) return } } -// ImportState imports the resource state. -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 +func (r *AppInstanceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index bef742b..e963239 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -2,9 +2,7 @@ package provider import ( "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/path" "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/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 ( - _ provider.Provider = &edgeConnectProvider{} -) +var _ provider.Provider = &EdgeConnectProvider{} -// New is a helper function to simplify provider server and testing implementation. -func New(version string) func() provider.Provider { - return func() provider.Provider { - return &edgeConnectProvider{ - version: version, - } - } -} - -// edgeConnectProvider is the provider implementation. -type edgeConnectProvider struct { +type EdgeConnectProvider struct { version string } -// edgeConnectProviderModel maps provider schema data to a Go type. -type edgeConnectProviderModel struct { - BaseURL types.String `tfsdk:"base_url"` +type EdgeConnectProviderModel struct { + Endpoint types.String `tfsdk:"endpoint"` 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(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) { +func (p *EdgeConnectProvider) Metadata(ctx context.Context, req provider.MetadataRequest, resp *provider.MetadataResponse) { resp.TypeName = "edge-connect" resp.Version = p.version } -// Schema defines the provider-level schema for configuration data. -func (p *edgeConnectProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) { +func (p *EdgeConnectProvider) Schema(ctx context.Context, req provider.SchemaRequest, resp *provider.SchemaResponse) { resp.Schema = schema.Schema{ - Description: "Interact with Edge Connect API for managing applications and application instances.", Attributes: map[string]schema.Attribute{ - "base_url": schema.StringAttribute{ - Description: "The base URL for the Edge Connect API. May also be provided via EDGE_CONNECT_BASE_URL environment variable.", - Optional: true, + "endpoint": schema.StringAttribute{ + MarkdownDescription: "Edge Connect API endpoint", + Required: true, }, "token": schema.StringAttribute{ - Description: "Bearer token for authentication. May also be provided via EDGE_CONNECT_TOKEN environment variable.", - Optional: 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, + MarkdownDescription: "Edge Connect API token", + Required: 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) { - tflog.Info(ctx, "Configuring Edge Connect client") +func (p *EdgeConnectProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { + var data EdgeConnectProviderModel + + 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() { return } - // If practitioner provided a configuration value for any of the - // attributes, it must be a known value. - if config.BaseURL.IsUnknown() { + endpoint := data.Endpoint.ValueString() + token := data.Token.ValueString() + + if endpoint == "" { resp.Diagnostics.AddAttributeError( - path.Root("base_url"), - "Unknown Edge Connect API Base URL", - "The provider cannot create the Edge Connect API client as there is an unknown configuration value for the base URL. "+ - "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.", + path.Root("endpoint"), + "Missing Edge Connect API Endpoint", + "The provider cannot create the Edge Connect API client as there is a missing or empty value for the Edge Connect API endpoint.", ) } - if config.Token.IsUnknown() { + if token == "" { resp.Diagnostics.AddAttributeError( path.Root("token"), - "Unknown Edge Connect API Token", - "The provider cannot create the Edge Connect API client as there is an unknown configuration value for the 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.", + "Missing Edge Connect API Token", + "The provider cannot create the Edge Connect API client as there is a missing or empty value for the Edge Connect API token.", ) } @@ -128,97 +78,37 @@ func (p *edgeConnectProvider) Configure(ctx context.Context, req provider.Config return } - // Default values to environment variables, but override - // 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.SetField(ctx, "edge_connect_endpoint", endpoint) ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "edge_connect_token") - ctx = tflog.MaskFieldValuesWithFieldKeys(ctx, "edge_connect_password") tflog.Debug(ctx, "Creating Edge Connect client") - // Create a new Edge Connect client using the configuration values - apiClient := client.NewClient(baseURL, token, username, password) + client := edgeclient.NewClient(endpoint) - // Test the connection - if err := apiClient.HealthCheck(); err != nil { - 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 + resp.DataSourceData = client + resp.ResourceData = client tflog.Info(ctx, "Configured Edge Connect client", map[string]any{"success": true}) } -// DataSources defines the data sources implemented in the provider. -func (p *edgeConnectProvider) DataSources(_ context.Context) []func() datasource.DataSource { - return []func() datasource.DataSource{ - NewAppDataSource, - NewAppInstDataSource, +func (p *EdgeConnectProvider) Resources(ctx context.Context) []func() resource.Resource { + return []func() resource.Resource{ + NewAppResource, + NewAppInstanceResource, } } -// Resources defines the resources implemented in the provider. -func (p *edgeConnectProvider) Resources(_ context.Context) []func() resource.Resource { - return []func() resource.Resource{ - NewAppResource, - NewAppInstResource, +func (p *EdgeConnectProvider) DataSources(ctx context.Context) []func() datasource.DataSource { + return []func() datasource.DataSource{ + NewAppDataSource, + NewAppInstanceDataSource, + } +} + +func New(version string) func() provider.Provider { + return func() provider.Provider { + return &EdgeConnectProvider{ + version: version, + } } }