package provider import ( "context" "fmt" "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" edgeclient "edp.buildth.ing/DevFW-CICD/edge-connect-client/v2/sdk/edgeconnect" ) var _ resource.Resource = &AppInstanceResource{} var _ resource.ResourceWithImportState = &AppInstanceResource{} func NewAppInstanceResource() resource.Resource { return &AppInstanceResource{} } type AppInstanceResource struct { client *edgeclient.Client } type AppInstanceResourceModel struct { Id types.String `tfsdk:"id"` Name types.String `tfsdk:"name"` Organization types.String `tfsdk:"organization"` Region types.String `tfsdk:"region"` CloudletOrg types.String `tfsdk:"cloudlet_org"` CloudletName types.String `tfsdk:"cloudlet_name"` AppName types.String `tfsdk:"app_name"` AppVersion types.String `tfsdk:"app_version"` AppOrganization types.String `tfsdk:"app_organization"` FlavorName types.String `tfsdk:"flavor_name"` State types.String `tfsdk:"state"` PowerState types.String `tfsdk:"power_state"` } func (r *AppInstanceResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_app_instance" } func (r *AppInstanceResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ MarkdownDescription: "EdgeConnect AppInstance deployment resource", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ Computed: true, MarkdownDescription: "AppInstance identifier", PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, "name": schema.StringAttribute{ MarkdownDescription: "AppInstance name", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "organization": schema.StringAttribute{ MarkdownDescription: "Organization name", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "region": schema.StringAttribute{ MarkdownDescription: "Region (e.g., US, EU)", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "cloudlet_org": schema.StringAttribute{ MarkdownDescription: "Cloudlet organization", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "cloudlet_name": schema.StringAttribute{ MarkdownDescription: "Cloudlet name", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "app_name": schema.StringAttribute{ MarkdownDescription: "Application name", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "app_version": schema.StringAttribute{ MarkdownDescription: "Application version", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "app_organization": schema.StringAttribute{ MarkdownDescription: "Application organization", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "flavor_name": schema.StringAttribute{ MarkdownDescription: "Flavor name", Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "state": schema.StringAttribute{ MarkdownDescription: "AppInstance state", Computed: true, }, "power_state": schema.StringAttribute{ MarkdownDescription: "AppInstance power state", Computed: true, }, }, } } func (r *AppInstanceResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { if req.ProviderData == nil { return } client, ok := req.ProviderData.(*edgeclient.Client) if !ok { resp.Diagnostics.AddError( "Unexpected Resource Configure Type", fmt.Sprintf("Expected *edgeclient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } r.client = client } 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 } appInstInput := &edgeclient.NewAppInstanceInput{ Region: data.Region.ValueString(), AppInst: edgeclient.AppInstance{ Key: edgeclient.AppInstanceKey{ Organization: data.Organization.ValueString(), Name: data.Name.ValueString(), CloudletKey: edgeclient.CloudletKey{ Organization: data.CloudletOrg.ValueString(), Name: data.CloudletName.ValueString(), }, }, AppKey: edgeclient.AppKey{ Organization: data.AppOrganization.ValueString(), Name: data.AppName.ValueString(), Version: data.AppVersion.ValueString(), }, Flavor: edgeclient.Flavor{Name: data.FlavorName.ValueString()}, }, } err := r.client.CreateAppInstance(ctx, appInstInput) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create app instance, got error: %s", err)) return } data.Id = types.StringValue(appInstInput.AppInst.Key.Name) data.State = types.StringValue("created") appInstance, err := r.client.ShowAppInstance(ctx, appInstInput.AppInst.Key, appInstInput.AppInst.AppKey, data.Region.ValueString()) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app instance %s, got error: %s", data.Id.ValueString(), err)) return } // Update state from API response UpdateDataFromAppInstance(&appInstance, &data) tflog.Trace(ctx, "created an app instance resource") resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } 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 } appInstKey := edgeclient.AppInstanceKey{ Organization: data.Organization.ValueString(), Name: data.Id.ValueString(), CloudletKey: edgeclient.CloudletKey{ Organization: data.CloudletOrg.ValueString(), Name: data.CloudletName.ValueString(), }, } appKey := edgeclient.AppKey{ Name: data.AppName.ValueString(), } appInstance, err := r.client.ShowAppInstance(ctx, appInstKey, appKey, data.Region.ValueString()) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app instance %s, got error: %s", data.Id.ValueString(), err)) return } // Update state from API response UpdateDataFromAppInstance(&appInstance, &data) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } 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 } updateInput := &edgeclient.UpdateAppInstanceInput{ Region: data.Region.ValueString(), AppInst: edgeclient.AppInstance{ Key: edgeclient.AppInstanceKey{ Organization: data.Organization.ValueString(), Name: data.Name.ValueString(), CloudletKey: edgeclient.CloudletKey{ Organization: data.CloudletOrg.ValueString(), Name: data.CloudletName.ValueString(), }, }, AppKey: edgeclient.AppKey{ Organization: data.AppOrganization.ValueString(), Name: data.AppName.ValueString(), Version: data.AppVersion.ValueString(), }, Flavor: edgeclient.Flavor{Name: data.FlavorName.ValueString()}, }, } appInput := edgeclient.AppKey{ Name: data.AppName.ValueString(), } err := r.client.UpdateAppInstance(ctx, updateInput) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update app instance, got error: %s", err)) return } appInstance, err := r.client.ShowAppInstance(ctx, updateInput.AppInst.Key, appInput, data.Region.ValueString()) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read app instance %s, got error: %s", data.Id.ValueString(), err)) return } // Update state from API response UpdateDataFromAppInstance(&appInstance, &data) data.State = types.StringValue("updated") resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) } 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 } appInstKey := edgeclient.AppInstanceKey{ Organization: data.Organization.ValueString(), Name: data.Id.ValueString(), CloudletKey: edgeclient.CloudletKey{ Organization: data.CloudletOrg.ValueString(), Name: data.CloudletName.ValueString(), }, } err := r.client.DeleteAppInstance(ctx, appInstKey, data.Region.ValueString()) if err != nil { resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete app instance, got error: %s", err)) return } } func (r *AppInstanceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) } func UpdateDataFromAppInstance(appInstance *edgeclient.AppInstance, data *AppInstanceResourceModel) { data.Name = types.StringValue(appInstance.Key.Name) data.Organization = types.StringValue(appInstance.Key.Organization) data.CloudletOrg = types.StringValue(appInstance.Key.CloudletKey.Organization) data.CloudletName = types.StringValue(appInstance.Key.CloudletKey.Name) data.AppName = types.StringValue(appInstance.AppKey.Name) data.AppVersion = types.StringValue(appInstance.AppKey.Version) data.AppOrganization = types.StringValue(appInstance.AppKey.Organization) data.FlavorName = types.StringValue(appInstance.Flavor.Name) data.State = types.StringValue(appInstance.State) data.PowerState = types.StringValue(appInstance.PowerState) }