feat: sdk migration in progress

This commit is contained in:
allanice001
2025-11-02 13:19:30 +00:00
commit 0d10d42442
492 changed files with 71067 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
BIN ?= terraform-provider-autoglue
VER ?= 0.0.1
OS ?= $(shell uname -s | tr '[:upper:]' '[:lower:]')
ARCH ?= $(shell uname -m | sed 's/x86_64/amd64/;s/arm64/arm64/')
.PHONY: build tidy dev clean
build:
go build -o $(BIN) .
tidy:
go mod tidy
dev:
@echo "Installing dev provider v$(VER) for $(OS)_$(ARCH)..."
@DST="$${HOME}/.terraform.d/plugins/glueops/autoglue/autoglue/$(VER)/$(OS)_$(ARCH)"; \
mkdir -p "$$DST"; \
go build -o "$$DST/terraform-provider-autoglue_v$(VER)" .; \
echo "Provider installed to $$DST"; \
echo "Run: terraform init -upgrade"
clean:
rm -f $(BIN)

View File

@@ -0,0 +1,36 @@
module github.com/glueops/terraform-provider-gsot
go 1.25.3
require (
github.com/glueops/autoglue-sdk v0.0.0-00010101000000-000000000000
github.com/hashicorp/terraform-plugin-framework v1.16.1
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0
)
require (
github.com/fatih/color v1.15.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.7.0 // 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-log v0.9.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/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/oklog/run v1.1.0 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // 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
)
replace github.com/glueops/autoglue-sdk => ../sdk/go

View File

@@ -0,0 +1,101 @@
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/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/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/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-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-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=
github.com/hashicorp/terraform-plugin-framework v1.16.1/go.mod h1:0xFOxLy5lRzDTayc4dzK/FakIgBhNf/lC4499R9cV4Y=
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0 h1:Zz3iGgzxe/1XBkooZCewS0nJAaCFPFPHdNJd8FgE4Ow=
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0/go.mod h1:GBKTNGbGVJohU03dZ7U8wHqc2zYnMUawgCN+gC0itLc=
github.com/hashicorp/terraform-plugin-go v0.29.0 h1:1nXKl/nSpaYIUBU1IG/EsDOX0vv+9JxAltQyDMpq5mU=
github.com/hashicorp/terraform-plugin-go v0.29.0/go.mod h1:vYZbIyvxyy0FWSmDHChCqKvI40cFTDGSb3D8D70i9GM=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-registry-address v0.4.0 h1:S1yCGomj30Sao4l5BMPjTGZmCNzuv7/GDTDX99E9gTk=
github.com/hashicorp/terraform-registry-address v0.4.0/go.mod h1:LRS1Ay0+mAiRkUyltGT+UHWkIqTFvigGn/LbMshfflE=
github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ=
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/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/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.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/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/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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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/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=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
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=
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=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
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/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,78 @@
package provider
import (
"context"
"net/http"
"github.com/glueops/autoglue-sdk"
"github.com/hashicorp/terraform-plugin-framework/diag"
)
type Client struct {
SDK *autoglue.APIClient
}
func NewClient(_ context.Context, cfg providerModel) (*Client, diag.Diagnostics) {
var diags diag.Diagnostics
conf := autoglue.NewConfiguration()
conf.Servers = autoglue.ServerConfigurations{{URL: cfg.Addr.ValueString()}}
// Attach auth headers for *every* request
rt := http.DefaultTransport
conf.HTTPClient = &http.Client{
Transport: headerRoundTripper{
under: rt,
bearer: strOrEmpty(cfg.Bearer),
apiKey: strOrEmpty(cfg.APIKey),
orgKey: strOrEmpty(cfg.OrgKey),
orgSecret: strOrEmpty(cfg.OrgSecret),
orgID: strOrEmpty(cfg.OrgID),
},
}
return &Client{SDK: autoglue.NewAPIClient(conf)}, diags
}
type headerRoundTripper struct {
under http.RoundTripper
bearer string
apiKey string
orgKey string
orgSecret string
orgID string
}
func (h headerRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
// Bearer -> Authorization
if h.bearer != "" {
req.Header.Set("Authorization", "Bearer "+h.bearer)
}
// User API Key
if h.apiKey != "" {
req.Header.Set("X-API-KEY", h.apiKey)
}
// Org key/secret
if h.orgKey != "" {
req.Header.Set("X-ORG-KEY", h.orgKey)
}
if h.orgSecret != "" {
req.Header.Set("X-ORG-SECRET", h.orgSecret)
}
// Org selection header (user or key where needed)
if h.orgID != "" {
req.Header.Set("X-Org-ID", h.orgID)
}
return h.under.RoundTrip(req)
}
func strOrEmpty(v interface {
IsNull() bool
IsUnknown() bool
ValueString() string
}) string {
if v.IsNull() || v.IsUnknown() {
return ""
}
return v.ValueString()
}

View File

@@ -0,0 +1,99 @@
package provider
import (
"context"
"os"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/provider"
pschema "github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
type providerModel struct {
Addr types.String `tfsdk:"addr"`
Bearer types.String `tfsdk:"bearer"`
APIKey types.String `tfsdk:"api_key"`
OrgKey types.String `tfsdk:"org_key"`
OrgSecret types.String `tfsdk:"org_secret"`
OrgID types.String `tfsdk:"org_id"`
}
func providerConfigSchema() map[string]pschema.Attribute {
return map[string]pschema.Attribute{
"addr": pschema.StringAttribute{
Optional: true,
Description: "Base URL to the autoglue API (e.g. https://gsot.example.com/api/v1). Defaults to http://localhost:8080/api/v1.",
},
"bearer": pschema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "Bearer token (user access token).",
},
"api_key": pschema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "User API key for key-only auth.",
},
"org_key": pschema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "Org-scoped key for machine auth.",
},
"org_secret": pschema.StringAttribute{
Optional: true,
Sensitive: true,
Description: "Org-scoped secret for machine auth.",
},
"org_id": pschema.StringAttribute{
Optional: true,
Description: "Organization ID (UUID). Required for user/bearer and user API key auth unless single-org membership. Omitted for org key/secret (derived server-side).",
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
},
}
}
func readConfig(ctx context.Context, req provider.ConfigureRequest) (providerModel, diag.Diagnostics) {
var cfg providerModel
var diags diag.Diagnostics
req.Config.Get(ctx, &cfg)
if cfg.Addr.IsNull() || cfg.Addr.IsUnknown() {
if v := os.Getenv("AUTOGLUE_ADDR"); v != "" {
cfg.Addr = types.StringValue(v)
} else {
cfg.Addr = types.StringValue("http://localhost:8080/api/v1")
}
}
if cfg.Bearer.IsNull() || cfg.Bearer.IsUnknown() {
if v := os.Getenv("AUTOGLUE_TOKEN"); v != "" {
cfg.Bearer = types.StringValue(v)
}
}
if cfg.APIKey.IsNull() || cfg.APIKey.IsUnknown() {
if v := os.Getenv("AUTOGLUE_API_KEY"); v != "" {
cfg.APIKey = types.StringValue(v)
}
}
if cfg.OrgKey.IsNull() || cfg.OrgKey.IsUnknown() {
if v := os.Getenv("AUTOGLUE_ORG_KEY"); v != "" {
cfg.OrgKey = types.StringValue(v)
}
}
if cfg.OrgSecret.IsNull() || cfg.OrgSecret.IsUnknown() {
if v := os.Getenv("AUTOGLUE_ORG_SECRET"); v != "" {
cfg.OrgSecret = types.StringValue(v)
}
}
if cfg.OrgID.IsNull() || cfg.OrgID.IsUnknown() {
if v := os.Getenv("AUTOGLUE_ORG_ID"); v != "" {
cfg.OrgID = types.StringValue(v)
} else {
cfg.OrgID = types.StringNull()
}
}
return cfg, diags
}

View File

@@ -0,0 +1,121 @@
package provider
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/terraform-plugin-framework/datasource"
dschema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
)
var _ datasource.DataSource = &SshDataSource{}
var _ datasource.DataSourceWithConfigure = &SshDataSource{}
type SshDataSource struct{ client *Client }
func NewSshDataSource() datasource.DataSource { return &SshDataSource{} }
type sshDSModel struct {
NameContains types.String `tfsdk:"name_contains"`
Fingerprint types.String `tfsdk:"fingerprint"`
Keys []sshItem `tfsdk:"keys"`
}
type sshItem struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
PublicKey types.String `tfsdk:"public_key"`
Fingerprint types.String `tfsdk:"fingerprint"`
CreatedAt types.String `tfsdk:"created_at"`
UpdatedAt types.String `tfsdk:"updated_at"`
}
func (d *SshDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_ssh_keys"
}
func (d *SshDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = dschema.Schema{
Attributes: map[string]dschema.Attribute{
"name_contains": dschema.StringAttribute{
Optional: true,
Description: "Filter by substring of name (client-side).",
},
"fingerprint": dschema.StringAttribute{
Optional: true,
Description: "Filter by exact fingerprint (client-side).",
},
"keys": dschema.ListNestedAttribute{
Computed: true,
Description: "SSH keys",
NestedObject: dschema.NestedAttributeObject{
Attributes: map[string]dschema.Attribute{
"id": dschema.StringAttribute{Computed: true},
"name": dschema.StringAttribute{Computed: true},
"public_key": dschema.StringAttribute{Computed: true},
"fingerprint": dschema.StringAttribute{Computed: true},
"created_at": dschema.StringAttribute{Computed: true},
"updated_at": dschema.StringAttribute{Computed: true},
},
},
},
},
}
}
func (d *SshDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, _ *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
d.client = req.ProviderData.(*Client)
}
func (d *SshDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
if d.client == nil || d.client.SDK == nil {
resp.Diagnostics.AddError("Client not configured", "Provider configuration missing")
return
}
var conf sshDSModel
resp.Diagnostics.Append(req.Config.Get(ctx, &conf)...)
if resp.Diagnostics.HasError() {
return
}
items, httpResp, err := d.client.SDK.SshAPI.ListPublicSshKeys(ctx).Execute()
if err != nil {
resp.Diagnostics.AddError("List ssh keys failed", fmt.Sprintf("%v", httpErr(err, httpResp)))
return
}
nc := strings.ToLower(conf.NameContains.ValueString())
fp := conf.Fingerprint.ValueString()
out := sshDSModel{NameContains: conf.NameContains, Fingerprint: conf.Fingerprint}
out.Keys = make([]sshItem, 0, len(items))
for _, s := range items {
name := ""
if s.Name != nil {
name = *s.Name
}
if nc != "" && !strings.Contains(strings.ToLower(name), nc) {
continue
}
if fp != "" && (s.Fingerprint == nil || *s.Fingerprint != fp) {
continue
}
out.Keys = append(out.Keys, sshItem{
ID: types.StringPointerValue(s.Id),
Name: types.StringPointerValue(s.Name),
PublicKey: types.StringPointerValue(s.PublicKey),
Fingerprint: types.StringPointerValue(s.Fingerprint),
CreatedAt: types.StringPointerValue(s.CreatedAt),
UpdatedAt: types.StringPointerValue(s.UpdatedAt),
})
}
resp.Diagnostics.Append(resp.State.Set(ctx, &out)...)
}

View File

@@ -0,0 +1,20 @@
package provider
import (
"fmt"
"io"
"net/http"
)
func httpErr(err error, resp *http.Response) string {
if resp == nil {
return err.Error()
}
defer resp.Body.Close()
b, _ := io.ReadAll(resp.Body)
return fmt.Sprintf("status=%d: %s (body=%s)", resp.StatusCode, resp.Status, string(b))
}
func isNotFound(resp *http.Response) bool {
return resp != nil && resp.StatusCode == http.StatusNotFound
}

View File

@@ -0,0 +1,14 @@
package provider
import "math"
func round6(x float64) float64 {
return math.Round(x*1e6) / 1e6
}
func f32ptrToTF64(v *float32) float64 {
if v == nil {
return 0
}
return round6(float64(*v))
}

View File

@@ -0,0 +1,58 @@
package provider
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/provider"
pschema "github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
)
var _ provider.Provider = &AutoglueProvider{}
func New() provider.Provider { return &AutoglueProvider{} }
type AutoglueProvider struct {
version string
}
func (p *AutoglueProvider) Metadata(_ context.Context, _ provider.MetadataRequest, resp *provider.MetadataResponse) {
resp.TypeName = "autoglue"
resp.Version = p.version
}
func (p *AutoglueProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = pschema.Schema{
Attributes: providerConfigSchema(),
}
}
func (p *AutoglueProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) {
cfg, diags := readConfig(ctx, req)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
client, diags := NewClient(ctx, cfg)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
resp.DataSourceData = client
resp.ResourceData = client
}
func (p *AutoglueProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
NewSshDataSource,
}
}
func (p *AutoglueProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
NewSshResource,
}
}

View File

@@ -0,0 +1,230 @@
package provider
import (
"context"
"fmt"
"github.com/glueops/autoglue-sdk"
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
rschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
)
var _ resource.Resource = &SshResource{}
var _ resource.ResourceWithConfigure = &SshResource{}
var _ resource.ResourceWithImportState = &SshResource{}
type SshResource struct{ client *Client }
func NewSshResource() resource.Resource { return &SshResource{} }
type sshResModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Comment types.String `tfsdk:"comment"`
Type types.String `tfsdk:"type"`
Bits types.Int64 `tfsdk:"bits"`
PublicKey types.String `tfsdk:"public_key"`
Fingerprint types.String `tfsdk:"fingerprint"`
CreatedAt types.String `tfsdk:"created_at"`
UpdatedAt types.String `tfsdk:"updated_at"`
PrivateKeyPEM types.String `tfsdk:"private_key_pem"` // not populated by resource
}
func (r *SshResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_ssh_key"
}
func (r *SshResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = rschema.Schema{
Attributes: map[string]rschema.Attribute{
"id": rschema.StringAttribute{
Computed: true,
Description: "SSH key ID (UUID)",
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"name": rschema.StringAttribute{
Required: true,
Description: "Display name",
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"comment": rschema.StringAttribute{
Required: true,
Description: "Comment appended to authorized key",
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"type": rschema.StringAttribute{
Optional: true,
Description: "Key type: rsa or ed25519 (default rsa)",
Validators: []validator.String{
stringvalidator.OneOf("rsa", "ed25519", ""),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"bits": rschema.Int64Attribute{
Optional: true,
Description: "RSA key size (2048/3072/4096). Ignored for ed25519.",
Validators: []validator.Int64{
int64validator.OneOf(2048, 3072, 4096),
},
PlanModifiers: []planmodifier.Int64{
int64planmodifier.RequiresReplace(),
},
},
"public_key": rschema.StringAttribute{
Computed: true,
Description: "OpenSSH authorized key",
},
"fingerprint": rschema.StringAttribute{
Computed: true,
Description: "SHA256 fingerprint",
},
"created_at": rschema.StringAttribute{
Computed: true,
Description: "Creation time (RFC3339, UTC)",
},
"updated_at": rschema.StringAttribute{
Computed: true,
Description: "Update time (RFC3339, UTC)",
},
"private_key_pem": rschema.StringAttribute{
Computed: true,
Sensitive: true,
Description: "Private key PEM (resource doesnt reveal; stays empty).",
},
},
}
}
func (r *SshResource) Configure(_ context.Context, req resource.ConfigureRequest, _ *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
r.client = req.ProviderData.(*Client)
}
func (r *SshResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
if r.client == nil || r.client.SDK == nil {
resp.Diagnostics.AddError("Client not configured", "Provider configuration missing")
return
}
var plan sshResModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}
body := autoglue.DtoCreateSSHRequest{
Name: plan.Name.ValueStringPointer(),
Comment: plan.Comment.ValueStringPointer(),
}
if t := plan.Type.ValueString(); t != "" {
body.Type = &t
}
if !plan.Bits.IsNull() && !plan.Bits.IsUnknown() {
b := int32(plan.Bits.ValueInt64())
body.Bits = &b
}
created, httpResp, err := r.client.SDK.SshAPI.CreateSSHKey(ctx).Body(body).Execute()
if err != nil {
resp.Diagnostics.AddError("Create ssh key failed", fmt.Sprintf("%v", httpErr(err, httpResp)))
return
}
state := sshResModel{
ID: types.StringPointerValue(created.Id),
Name: types.StringPointerValue(created.Name),
Comment: plan.Comment,
Type: plan.Type,
Bits: plan.Bits,
PublicKey: types.StringPointerValue(created.PublicKey),
Fingerprint: types.StringPointerValue(created.Fingerprint),
CreatedAt: types.StringPointerValue(created.CreatedAt),
UpdatedAt: types.StringPointerValue(created.UpdatedAt),
// PrivateKeyPEM left empty (no reveal on resource)
}
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
func (r *SshResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
if r.client == nil || r.client.SDK == nil {
resp.Diagnostics.AddError("Client not configured", "Provider configuration missing")
return
}
var state sshResModel
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
got, httpResp, err := r.client.SDK.SshAPI.GetSSHKey(ctx, state.ID.ValueString()).Execute()
if err != nil {
if isNotFound(httpResp) {
resp.State.RemoveResource(ctx)
return
}
resp.Diagnostics.AddError("Read ssh key failed", fmt.Sprintf("%v", httpErr(err, httpResp)))
return
}
// Map from flat fields on DtoSshRevealResponse
state.Name = types.StringPointerValue(got.Name)
state.PublicKey = types.StringPointerValue(got.PublicKey)
state.Fingerprint = types.StringPointerValue(got.Fingerprint)
state.CreatedAt = types.StringPointerValue(got.CreatedAt)
state.UpdatedAt = types.StringPointerValue(got.UpdatedAt)
// We intentionally do NOT set PrivateKeyPEM here (resource doesn't reveal)
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
func (r *SshResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
// All changes are RequiresReplace; no server-side update.
var state sshResModel
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}
func (r *SshResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
if r.client == nil || r.client.SDK == nil {
resp.Diagnostics.AddError("Client not configured", "Provider configuration missing")
return
}
var state sshResModel
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
_, httpResp, err := r.client.SDK.SshAPI.DeleteSSHKey(ctx, state.ID.ValueString()).Execute()
if err != nil && !isNotFound(httpResp) {
resp.Diagnostics.AddError("Delete ssh key failed", fmt.Sprintf("%v", httpErr(err, httpResp)))
}
}
func (r *SshResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), req.ID)...)
}

View File

@@ -0,0 +1,25 @@
package main
import (
"context"
"flag"
"github.com/glueops/terraform-provider-gsot/internal/provider"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
)
var (
version = "0.10.0"
)
func main() {
var debug bool
flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve")
flag.Parse()
providerserver.Serve(context.Background(), provider.New, providerserver.ServeOpts{
Address: "terraform.gpkg.io/glueops/autoglue", //"registry.terraform.io/glueops/autoglue",
Debug: debug,
})
}