2025-11-11 14:15:52 +01:00
package provider
import (
"context"
2025-11-11 17:05:34 +01:00
"fmt"
2025-11-11 15:55:38 +01:00
"net/http"
2025-11-11 15:41:07 +01:00
"os"
2025-11-11 15:55:38 +01:00
"time"
2025-11-11 14:15:52 +01:00
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/provider"
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
2025-11-17 16:31:11 +01:00
edgeclient "edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/sdk/edgeconnect/v2"
2025-11-11 14:15:52 +01:00
)
2025-11-11 15:25:57 +01:00
var _ provider . Provider = & EdgeConnectProvider { }
2025-11-11 14:15:52 +01:00
2025-11-11 15:25:57 +01:00
type EdgeConnectProvider struct {
2025-11-11 14:15:52 +01:00
version string
}
2025-11-11 15:25:57 +01:00
type EdgeConnectProviderModel struct {
Endpoint types . String ` tfsdk:"endpoint" `
2025-11-11 14:15:52 +01:00
Token types . String ` tfsdk:"token" `
2025-11-11 15:35:39 +01:00
Username types . String ` tfsdk:"username" `
Password types . String ` tfsdk:"password" `
2025-11-11 14:15:52 +01:00
}
2025-11-11 15:25:57 +01:00
func ( p * EdgeConnectProvider ) Metadata ( ctx context . Context , req provider . MetadataRequest , resp * provider . MetadataResponse ) {
2025-11-11 14:15:52 +01:00
resp . TypeName = "edge-connect"
resp . Version = p . version
}
2025-11-11 15:25:57 +01:00
func ( p * EdgeConnectProvider ) Schema ( ctx context . Context , req provider . SchemaRequest , resp * provider . SchemaResponse ) {
2025-11-11 14:15:52 +01:00
resp . Schema = schema . Schema {
2025-11-11 15:41:07 +01:00
MarkdownDescription : "Provider for Edge Connect API. Supports authentication via token or username/password. " +
"Configuration can be provided via attributes or environment variables." ,
2025-11-11 14:15:52 +01:00
Attributes : map [ string ] schema . Attribute {
2025-11-11 15:25:57 +01:00
"endpoint" : schema . StringAttribute {
2025-11-11 15:41:07 +01:00
MarkdownDescription : "Edge Connect API endpoint. Can also be set via `EDGE_CONNECT_ENDPOINT` environment variable." ,
Optional : true ,
2025-11-11 14:15:52 +01:00
} ,
"token" : schema . StringAttribute {
2025-11-11 15:41:07 +01:00
MarkdownDescription : "Edge Connect API token. Required if username/password are not provided. " +
"Can also be set via `EDGE_CONNECT_TOKEN` environment variable." ,
Optional : true ,
Sensitive : true ,
2025-11-11 15:35:39 +01:00
} ,
"username" : schema . StringAttribute {
2025-11-11 15:41:07 +01:00
MarkdownDescription : "Edge Connect API username. Required if token is not provided. " +
"Can also be set via `EDGE_CONNECT_USERNAME` environment variable." ,
Optional : true ,
2025-11-11 15:35:39 +01:00
} ,
"password" : schema . StringAttribute {
2025-11-11 15:41:07 +01:00
MarkdownDescription : "Edge Connect API password. Required if token is not provided. " +
"Can also be set via `EDGE_CONNECT_PASSWORD` environment variable." ,
Optional : true ,
Sensitive : true ,
2025-11-11 14:15:52 +01:00
} ,
} ,
}
}
2025-11-11 15:25:57 +01:00
func ( p * EdgeConnectProvider ) Configure ( ctx context . Context , req provider . ConfigureRequest , resp * provider . ConfigureResponse ) {
var data EdgeConnectProviderModel
2025-11-11 14:15:52 +01:00
2025-11-11 15:25:57 +01:00
resp . Diagnostics . Append ( req . Config . Get ( ctx , & data ) ... )
2025-11-11 14:15:52 +01:00
if resp . Diagnostics . HasError ( ) {
return
}
2025-11-11 15:41:07 +01:00
// Read configuration values, falling back to environment variables
2025-11-11 15:25:57 +01:00
endpoint := data . Endpoint . ValueString ( )
2025-11-11 15:41:07 +01:00
if endpoint == "" {
endpoint = os . Getenv ( "EDGE_CONNECT_ENDPOINT" )
}
2025-11-11 15:25:57 +01:00
token := data . Token . ValueString ( )
2025-11-11 15:41:07 +01:00
if token == "" {
token = os . Getenv ( "EDGE_CONNECT_TOKEN" )
}
2025-11-11 15:35:39 +01:00
username := data . Username . ValueString ( )
2025-11-11 15:41:07 +01:00
if username == "" {
username = os . Getenv ( "EDGE_CONNECT_USERNAME" )
}
2025-11-11 15:35:39 +01:00
password := data . Password . ValueString ( )
2025-11-11 15:41:07 +01:00
if password == "" {
password = os . Getenv ( "EDGE_CONNECT_PASSWORD" )
}
2025-11-11 14:15:52 +01:00
2025-11-11 15:35:39 +01:00
// Validate endpoint
2025-11-11 15:25:57 +01:00
if endpoint == "" {
2025-11-11 14:15:52 +01:00
resp . Diagnostics . AddAttributeError (
2025-11-11 15:25:57 +01:00
path . Root ( "endpoint" ) ,
"Missing Edge Connect API Endpoint" ,
2025-11-11 15:41:07 +01:00
"The provider cannot create the Edge Connect API client as there is a missing or empty value for the Edge Connect API endpoint. " +
"Set the endpoint value in the configuration or use the EDGE_CONNECT_ENDPOINT environment variable." ,
2025-11-11 14:15:52 +01:00
)
}
2025-11-11 15:35:39 +01:00
// Validate authentication: either token OR username/password must be provided
hasToken := token != ""
hasUsernamePassword := username != "" && password != ""
if ! hasToken && ! hasUsernamePassword {
resp . Diagnostics . AddError (
"Missing Authentication Credentials" ,
"The provider requires authentication credentials. Please provide either:\n" +
2025-11-11 15:41:07 +01:00
" - token: API token for authentication (via 'token' attribute or EDGE_CONNECT_TOKEN environment variable), or\n" +
" - username and password: Username and password for authentication (via 'username'/'password' attributes or EDGE_CONNECT_USERNAME/EDGE_CONNECT_PASSWORD environment variables)" ,
2025-11-11 15:35:39 +01:00
)
}
if hasToken && hasUsernamePassword {
resp . Diagnostics . AddError (
"Conflicting Authentication Methods" ,
"Both token and username/password authentication methods are provided. Please use only one authentication method." ,
)
}
// Validate username/password pair
if ( username != "" && password == "" ) || ( username == "" && password != "" ) {
resp . Diagnostics . AddError (
"Incomplete Username/Password Credentials" ,
"Both username and password must be provided together for username/password authentication." ,
2025-11-11 14:15:52 +01:00
)
}
if resp . Diagnostics . HasError ( ) {
return
}
2025-11-11 15:25:57 +01:00
ctx = tflog . SetField ( ctx , "edge_connect_endpoint" , endpoint )
2025-11-11 14:15:52 +01:00
2025-11-11 15:35:39 +01:00
if hasToken {
ctx = tflog . MaskFieldValuesWithFieldKeys ( ctx , "edge_connect_token" )
tflog . Debug ( ctx , "Creating Edge Connect client with token authentication" )
} else {
ctx = tflog . SetField ( ctx , "edge_connect_username" , username )
ctx = tflog . MaskFieldValuesWithFieldKeys ( ctx , "edge_connect_password" )
tflog . Debug ( ctx , "Creating Edge Connect client with username/password authentication" )
}
2025-11-11 14:15:52 +01:00
2025-11-11 15:55:38 +01:00
var client * edgeclient . Client
if token != "" {
client = edgeclient . NewClient ( endpoint ,
2025-11-13 12:12:34 +01:00
edgeclient . WithHTTPClient ( & http . Client { Timeout : 30 * time . Second } ) ,
2025-11-11 15:55:38 +01:00
edgeclient . WithAuthProvider ( edgeclient . NewStaticTokenProvider ( token ) ) ,
2025-11-11 17:20:04 +01:00
edgeclient . WithLogger ( tfLogger { } ) ,
2025-11-11 15:55:38 +01:00
)
} else {
client = edgeclient . NewClientWithCredentials ( endpoint , username , password ,
2025-11-13 12:12:34 +01:00
edgeclient . WithHTTPClient ( & http . Client { Timeout : 30 * time . Second } ) ,
2025-11-11 17:20:04 +01:00
edgeclient . WithLogger ( tfLogger { } ) ,
2025-11-11 15:55:38 +01:00
)
}
2025-11-11 15:35:39 +01:00
// TODO: Configure client with authentication credentials
// If using token: client.SetToken(token)
// If using username/password: client.SetCredentials(username, password)
2025-11-11 15:25:57 +01:00
resp . DataSourceData = client
resp . ResourceData = client
2025-11-11 14:15:52 +01:00
tflog . Info ( ctx , "Configured Edge Connect client" , map [ string ] any { "success" : true } )
}
2025-11-11 15:25:57 +01:00
func ( p * EdgeConnectProvider ) Resources ( ctx context . Context ) [ ] func ( ) resource . Resource {
return [ ] func ( ) resource . Resource {
NewAppResource ,
NewAppInstanceResource ,
}
}
func ( p * EdgeConnectProvider ) DataSources ( ctx context . Context ) [ ] func ( ) datasource . DataSource {
2025-11-11 14:15:52 +01:00
return [ ] func ( ) datasource . DataSource {
NewAppDataSource ,
2025-11-11 15:25:57 +01:00
NewAppInstanceDataSource ,
2025-11-11 14:15:52 +01:00
}
}
2025-11-11 15:25:57 +01:00
func New ( version string ) func ( ) provider . Provider {
return func ( ) provider . Provider {
return & EdgeConnectProvider {
version : version ,
}
2025-11-11 14:15:52 +01:00
}
}
2025-11-11 17:05:34 +01:00
2025-11-13 12:12:34 +01:00
type tfLogger struct { }
2025-11-11 17:05:34 +01:00
2025-11-13 12:12:34 +01:00
func ( tfLogger ) Printf ( format string , v ... interface { } ) {
2025-11-11 17:20:04 +01:00
tflog . Debug ( context . TODO ( ) , fmt . Sprintf ( format , v ... ) )
2025-11-11 17:05:34 +01:00
}