init
This commit is contained in:
commit
51c743fb2b
17 changed files with 2387 additions and 0 deletions
177
internal/provider/app_data_source.go
Normal file
177
internal/provider/app_data_source.go
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
package provider
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
var (
|
||||
_ datasource.DataSource = &appDataSource{}
|
||||
_ datasource.DataSourceWithConfigure = &appDataSource{}
|
||||
)
|
||||
|
||||
// NewAppDataSource is a helper function to simplify the provider implementation.
|
||||
func NewAppDataSource() datasource.DataSource {
|
||||
return &appDataSource{}
|
||||
}
|
||||
|
||||
// appDataSource is the data source implementation.
|
||||
type appDataSource struct {
|
||||
client *client.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"`
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
func (d *appDataSource) Metadata(_ 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) {
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "Fetches an Edge Connect application specification.",
|
||||
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,
|
||||
},
|
||||
"name": schema.StringAttribute{
|
||||
Description: "The name of the application.",
|
||||
Required: true,
|
||||
},
|
||||
"version": schema.StringAttribute{
|
||||
Description: "The version of the application.",
|
||||
Required: 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,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Configure adds the provider configured client to the data source.
|
||||
func (d *appDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(*client.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),
|
||||
)
|
||||
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...)
|
||||
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()
|
||||
|
||||
readApp, err := d.client.GetApp(config.Region.ValueString(), app)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error reading app",
|
||||
"Could not read app: "+err.Error(),
|
||||
)
|
||||
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)
|
||||
|
||||
diags = resp.State.Set(ctx, &config)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
}
|
||||
311
internal/provider/app_resource.go
Normal file
311
internal/provider/app_resource.go
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
package provider
|
||||
|
||||
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"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
)
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
var (
|
||||
_ resource.Resource = &appResource{}
|
||||
_ resource.ResourceWithConfigure = &appResource{}
|
||||
_ resource.ResourceWithImportState = &appResource{}
|
||||
)
|
||||
|
||||
// NewAppResource is a helper function to simplify the provider implementation.
|
||||
func NewAppResource() resource.Resource {
|
||||
return &appResource{}
|
||||
}
|
||||
|
||||
// appResource is the resource implementation.
|
||||
type appResource struct {
|
||||
client *client.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"`
|
||||
}
|
||||
|
||||
// Metadata returns the resource type name.
|
||||
func (r *appResource) Metadata(_ 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) {
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "Manages an Edge Connect application specification.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": schema.StringAttribute{
|
||||
Description: "The unique identifier for the app (format: region/organization/name/version).",
|
||||
Computed: true,
|
||||
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(),
|
||||
},
|
||||
},
|
||||
"version": schema.StringAttribute{
|
||||
Description: "The version of the application.",
|
||||
Required: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
},
|
||||
},
|
||||
"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,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Configure adds the provider configured client to the resource.
|
||||
func (r *appResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(*client.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),
|
||||
)
|
||||
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...)
|
||||
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(),
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error creating app",
|
||||
"Could not create app: "+err.Error(),
|
||||
)
|
||||
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)
|
||||
|
||||
tflog.Trace(ctx, "created app resource")
|
||||
|
||||
diags = resp.State.Set(ctx, plan)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
}
|
||||
|
||||
// Read refreshes the Terraform state with the latest data.
|
||||
func (r *appResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
|
||||
var state appResourceModel
|
||||
diags := req.State.Get(ctx, &state)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
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()
|
||||
|
||||
readApp, err := r.client.GetApp(state.Region.ValueString(), app)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error reading app",
|
||||
"Could not read app: "+err.Error(),
|
||||
)
|
||||
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)
|
||||
|
||||
diags = resp.State.Set(ctx, &state)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
}
|
||||
|
||||
// Update updates the resource and sets the updated Terraform state on success.
|
||||
func (r *appResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
|
||||
var plan appResourceModel
|
||||
diags := req.Plan.Get(ctx, &plan)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
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(),
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error updating app",
|
||||
"Could not update app: "+err.Error(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Update computed attributes
|
||||
plan.UpdatedAt = types.StringValue(updatedApp.UpdatedAt)
|
||||
|
||||
diags = resp.State.Set(ctx, plan)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
}
|
||||
|
||||
// Delete deletes the resource and removes the Terraform state on success.
|
||||
func (r *appResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
|
||||
var state appResourceModel
|
||||
diags := req.State.Get(ctx, &state)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
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()
|
||||
|
||||
err := r.client.DeleteApp(state.Region.ValueString(), app)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error deleting app",
|
||||
"Could not delete app: "+err.Error(),
|
||||
)
|
||||
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
|
||||
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
|
||||
}
|
||||
204
internal/provider/appinst_data_source.go
Normal file
204
internal/provider/appinst_data_source.go
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
package provider
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
var (
|
||||
_ datasource.DataSource = &appInstDataSource{}
|
||||
_ datasource.DataSourceWithConfigure = &appInstDataSource{}
|
||||
)
|
||||
|
||||
// NewAppInstDataSource is a helper function to simplify the provider implementation.
|
||||
func NewAppInstDataSource() datasource.DataSource {
|
||||
return &appInstDataSource{}
|
||||
}
|
||||
|
||||
// appInstDataSource is the data source implementation.
|
||||
type appInstDataSource struct {
|
||||
client *client.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"`
|
||||
}
|
||||
|
||||
// Metadata returns the data source type name.
|
||||
func (d *appInstDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_appinst"
|
||||
}
|
||||
|
||||
// Schema defines the schema for the data source.
|
||||
func (d *appInstDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "Fetches an Edge Connect application instance.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": schema.StringAttribute{
|
||||
Description: "The unique identifier for the app instance.",
|
||||
Computed: true,
|
||||
},
|
||||
"region": schema.StringAttribute{
|
||||
Description: "The region where the app instance is deployed (e.g., 'EU').",
|
||||
Required: true,
|
||||
},
|
||||
"app_organization": schema.StringAttribute{
|
||||
Description: "The organization that owns the app.",
|
||||
Required: true,
|
||||
},
|
||||
"app_name": schema.StringAttribute{
|
||||
Description: "The name of the application.",
|
||||
Required: true,
|
||||
},
|
||||
"app_version": schema.StringAttribute{
|
||||
Description: "The version of the application.",
|
||||
Required: 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,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Configure adds the provider configured client to the data source.
|
||||
func (d *appInstDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(*client.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),
|
||||
)
|
||||
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...)
|
||||
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()
|
||||
|
||||
readAppInst, err := d.client.GetAppInst(config.Region.ValueString(), appInst)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error reading app instance",
|
||||
"Could not read app instance: "+err.Error(),
|
||||
)
|
||||
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)
|
||||
|
||||
diags = resp.State.Set(ctx, &config)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
}
|
||||
351
internal/provider/appinst_resource.go
Normal file
351
internal/provider/appinst_resource.go
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
package provider
|
||||
|
||||
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"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
|
||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||
)
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
var (
|
||||
_ resource.Resource = &appInstResource{}
|
||||
_ resource.ResourceWithConfigure = &appInstResource{}
|
||||
_ resource.ResourceWithImportState = &appInstResource{}
|
||||
)
|
||||
|
||||
// NewAppInstResource is a helper function to simplify the provider implementation.
|
||||
func NewAppInstResource() resource.Resource {
|
||||
return &appInstResource{}
|
||||
}
|
||||
|
||||
// appInstResource is the resource implementation.
|
||||
type appInstResource struct {
|
||||
client *client.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"`
|
||||
}
|
||||
|
||||
// Metadata returns the resource type name.
|
||||
func (r *appInstResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_appinst"
|
||||
}
|
||||
|
||||
// Schema defines the schema for the resource.
|
||||
func (r *appInstResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
resp.Schema = schema.Schema{
|
||||
Description: "Manages an Edge Connect application instance.",
|
||||
Attributes: map[string]schema.Attribute{
|
||||
"id": schema.StringAttribute{
|
||||
Description: "The unique identifier for the app instance.",
|
||||
Computed: true,
|
||||
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(),
|
||||
},
|
||||
},
|
||||
"app_organization": schema.StringAttribute{
|
||||
Description: "The organization that owns the app.",
|
||||
Required: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
},
|
||||
},
|
||||
"app_name": schema.StringAttribute{
|
||||
Description: "The name of the application.",
|
||||
Required: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
},
|
||||
},
|
||||
"app_version": schema.StringAttribute{
|
||||
Description: "The version of the application.",
|
||||
Required: true,
|
||||
PlanModifiers: []planmodifier.String{
|
||||
stringplanmodifier.RequiresReplace(),
|
||||
},
|
||||
},
|
||||
"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,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Configure adds the provider configured client to the resource.
|
||||
func (r *appInstResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
|
||||
if req.ProviderData == nil {
|
||||
return
|
||||
}
|
||||
|
||||
client, ok := req.ProviderData.(*client.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),
|
||||
)
|
||||
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...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
// Create new app instance
|
||||
appInst := client.AppInst{
|
||||
Cloudlet: plan.Cloudlet.ValueString(),
|
||||
Flavor: plan.Flavor.ValueString(),
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error creating app instance",
|
||||
"Could not create app instance: "+err.Error(),
|
||||
)
|
||||
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)
|
||||
|
||||
tflog.Trace(ctx, "created app instance resource")
|
||||
|
||||
diags = resp.State.Set(ctx, plan)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
}
|
||||
|
||||
// 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...)
|
||||
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()
|
||||
|
||||
readAppInst, err := r.client.GetAppInst(state.Region.ValueString(), appInst)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error reading app instance",
|
||||
"Could not read app instance: "+err.Error(),
|
||||
)
|
||||
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)
|
||||
|
||||
diags = resp.State.Set(ctx, &state)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
}
|
||||
|
||||
// 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...)
|
||||
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(),
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error updating app instance",
|
||||
"Could not update app instance: "+err.Error(),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// Update computed attributes
|
||||
plan.State = types.StringValue(updatedAppInst.State)
|
||||
plan.UpdatedAt = types.StringValue(updatedAppInst.UpdatedAt)
|
||||
|
||||
diags = resp.State.Set(ctx, plan)
|
||||
resp.Diagnostics.Append(diags...)
|
||||
}
|
||||
|
||||
// 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...)
|
||||
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()
|
||||
|
||||
err := r.client.DeleteAppInst(state.Region.ValueString(), appInst)
|
||||
if err != nil {
|
||||
resp.Diagnostics.AddError(
|
||||
"Error deleting app instance",
|
||||
"Could not delete app instance: "+err.Error(),
|
||||
)
|
||||
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
|
||||
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
|
||||
}
|
||||
224
internal/provider/provider.go
Normal file
224
internal/provider/provider.go
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
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"
|
||||
"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"
|
||||
)
|
||||
|
||||
// Ensure the implementation satisfies the expected interfaces.
|
||||
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 {
|
||||
version string
|
||||
}
|
||||
|
||||
// edgeConnectProviderModel maps provider schema data to a Go type.
|
||||
type edgeConnectProviderModel struct {
|
||||
BaseURL types.String `tfsdk:"base_url"`
|
||||
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) {
|
||||
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) {
|
||||
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,
|
||||
},
|
||||
"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,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
// 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() {
|
||||
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.",
|
||||
)
|
||||
}
|
||||
|
||||
if config.Token.IsUnknown() {
|
||||
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.",
|
||||
)
|
||||
}
|
||||
|
||||
if resp.Diagnostics.HasError() {
|
||||
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.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)
|
||||
|
||||
// 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
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
// Resources defines the resources implemented in the provider.
|
||||
func (p *edgeConnectProvider) Resources(_ context.Context) []func() resource.Resource {
|
||||
return []func() resource.Resource{
|
||||
NewAppResource,
|
||||
NewAppInstResource,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue