Skip to content

Commit

Permalink
feat: Add resource cloudavenue_backup
Browse files Browse the repository at this point in the history
  • Loading branch information
David MICHENEAU committed Oct 6, 2023
1 parent 0b6b13a commit 13aa297
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 50 deletions.
110 changes: 78 additions & 32 deletions internal/provider/backup/backup_resource.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package netbackup
package backup

import (
"context"
"fmt"

"github.com/orange-cloudavenue/netbackup-sdk-go/netbackupclient"

"github.com/hashicorp/terraform-plugin-framework/diag"

"github.com/hashicorp/terraform-plugin-framework/resource"
Expand All @@ -13,36 +15,35 @@ import (

// Ensure the implementation satisfies the expected interfaces.
var (
_ resource.Resource = &BackupResource{}
_ resource.ResourceWithConfigure = &BackupResource{}
_ resource.ResourceWithImportState = &BackupResource{}
// _ resource.ResourceWithModifyPlan = &BackupResource{}
// _ resource.ResourceWithUpgradeState = &BackupResource{}
// _ resource.ResourceWithValidateConfig = &BackupResource{}.
_ resource.Resource = &backupResource{}
_ resource.ResourceWithConfigure = &backupResource{}
_ resource.ResourceWithImportState = &backupResource{}
// _ resource.ResourceWithModifyPlan = &backupResource{}
// _ resource.ResourceWithUpgradeState = &backupResource{}
// _ resource.ResourceWithValidateConfig = &backupResource{}.
)

// NewBackupResource is a helper function to simplify the provider implementation.
// NewbackupResource is a helper function to simplify the provider implementation.
func NewBackupResource() resource.Resource {
return &BackupResource{}
return &backupResource{}
}

// BackupResource is the resource implementation.
type BackupResource struct {
// backupResource is the resource implementation.
type backupResource struct {
client *client.CloudAvenue

// Uncomment the following lines if you need to access the resource's.
// org org.Org
// vdc vdc.VDC
// vdc vdc.VDC
// vapp vapp.VAPP
}

// If the resource don't have same schema/structure as the data source, you can use the following code:
// type BackupResourceModel struct {
// type backupResourceModel struct {
// ID types.String `tfsdk:"id"`
// }

// Init Initializes the resource.
func (r *BackupResource) Init(ctx context.Context, rm *BackupModel) (diags diag.Diagnostics) {
func (r *backupResource) Init(ctx context.Context, rm *backupModel) (diags diag.Diagnostics) {
// Uncomment the following lines if you need to access to the Org
// r.org, diags = org.Init(r.client)
// if diags.HasError() {
Expand All @@ -62,16 +63,16 @@ func (r *BackupResource) Init(ctx context.Context, rm *BackupModel) (diags diag.
}

// Metadata returns the resource type name.
func (r *BackupResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
func (r *backupResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_" + categoryName
}

// Schema defines the schema for the resource.
func (r *BackupResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
func (r *backupResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = backupSchema(ctx).GetResource(ctx)
}

func (r *BackupResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
func (r *backupResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
// Prevent panic if the provider has not been configured.
if req.ProviderData == nil {
return
Expand All @@ -89,8 +90,8 @@ func (r *BackupResource) Configure(ctx context.Context, req resource.ConfigureRe
}

// Create creates the resource and sets the initial Terraform state.
func (r *BackupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
plan := &BackupModel{}
func (r *backupResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
plan := &backupModel{}

// Retrieve values from plan
resp.Diagnostics.Append(req.Plan.Get(ctx, plan)...)
Expand All @@ -108,20 +109,65 @@ func (r *BackupResource) Create(ctx context.Context, req resource.CreateRequest,
Implement the resource creation logic here.
*/

// Use generic read function to refresh the state
state, _, d := r.read(ctx, plan)
// Define if the target is a VDC ID or a VDC Name
var nameOrID string
if plan.TargetID.IsNull() {
nameOrID = plan.TargetName.Get()
} else {
nameOrID = plan.TargetID.Get()
}

// for policies extract values from the plan
policies, d := plan.GetPolicies(ctx)
if d.HasError() {
resp.Diagnostics.Append(d...)
return
}

// switch on the type of the backup
switch plan.Type.Get() {
case "vdc":
vdc, err := r.client.NetBackupClient.VCloud.GetVdcByNameOrIdentifier(nameOrID)
if err != nil {
resp.Diagnostics.AddError("Error getting vCloud Director Virtual Data Center", err.Error())
return
}
// for each policy, protect the VDC
for _, policy := range policies {
if policy.Enabled.Get() {
job, err := vdc.Protect(netbackupclient.ProtectUnprotectRequest{
ProtectionLevelName: policy.PolicyName.Get(),
ProtectionLevelID: policy.PolicyID.GetIntPtr(),
})
if err != nil {
resp.Diagnostics.AddError("Error protecting vCloud Director Virtual Data Center", err.Error())
return
}
if err := job.Wait(1, 15); err != nil {
resp.Diagnostics.AddError("Error waiting for job", err.Error())
}
}
}
case "vapp":
// TODO: Create a backup for a VAPP
case "vm":
// TODO: Create a backup for a VM
}

// Use generic read function to refresh the state
// state, _, d := r.read(ctx, plan)
// if d.HasError() {
// resp.Diagnostics.Append(d...)
// return
// }

// Set state to fully populated data
resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
resp.Diagnostics.Append(resp.State.Set(ctx, plan)...)
}

// Read refreshes the Terraform state with the latest data.
func (r *BackupResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
state := &BackupModel{}
func (r *backupResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
state := &backupModel{}

// Get current state
resp.Diagnostics.Append(req.State.Get(ctx, state)...)
Expand Down Expand Up @@ -151,10 +197,10 @@ func (r *BackupResource) Read(ctx context.Context, req resource.ReadRequest, res
}

// Update updates the resource and sets the updated Terraform state on success.
func (r *BackupResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
func (r *backupResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var (
plan = &BackupModel{}
state = &BackupModel{}
plan = &backupModel{}
state = &backupModel{}
)

// Get current plan and state
Expand Down Expand Up @@ -186,8 +232,8 @@ func (r *BackupResource) Update(ctx context.Context, req resource.UpdateRequest,
}

// Delete deletes the resource and removes the Terraform state on success.
func (r *BackupResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
state := &BackupModel{}
func (r *backupResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
state := &backupModel{}

// Get current state
resp.Diagnostics.Append(req.State.Get(ctx, state)...)
Expand All @@ -206,7 +252,7 @@ func (r *BackupResource) Delete(ctx context.Context, req resource.DeleteRequest,
*/
}

func (r *BackupResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
func (r *backupResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
// * Import basic
// resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)

Expand All @@ -228,7 +274,7 @@ func (r *BackupResource) ImportState(ctx context.Context, req resource.ImportSta
// * CustomFuncs

// read is a generic read function that can be used by the resource Create, Read and Update functions.
func (r *BackupResource) read(ctx context.Context, planOrState *BackupModel) (stateRefreshed *BackupModel, found bool, diags diag.Diagnostics) {
func (r *backupResource) read(ctx context.Context, planOrState *backupModel) (stateRefreshed *backupModel, found bool, diags diag.Diagnostics) {
// TODO : Remove the comment line after you have run the types generator
// stateRefreshed is commented because the Copy function is not before run the types generator
// stateRefreshed = planOrState.Copy()
Expand Down
23 changes: 12 additions & 11 deletions internal/provider/backup/backup_schema.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package netbackup
package backup

import (
"context"
Expand Down Expand Up @@ -94,7 +94,7 @@ func backupSchema(_ context.Context) superschema.Schema {
Resource: &schemaR.StringAttribute{
Required: true,
Validators: []validator.String{
stringvalidator.OneOf("vdc", "vapp", "vm"),
stringvalidator.OneOf("vdc", "VDC", "VAPP", "vapp", "VM", "vm"),
},
},
DataSource: &schemaD.StringAttribute{
Expand Down Expand Up @@ -147,16 +147,17 @@ func backupSchema(_ context.Context) superschema.Schema {
Computed: true,
},
Attributes: map[string]superschema.Attribute{
"policy_id": superschema.SuperStringAttribute{
Common: &schemaR.StringAttribute{
"policy_id": superschema.SuperInt64Attribute{
Common: &schemaR.Int64Attribute{
MarkdownDescription: "The ID of the backup policy.",
Computed: true,
},
Resource: &schemaR.StringAttribute{
Resource: &schemaR.Int64Attribute{
Optional: true,
Validators: []validator.String{
stringvalidator.ExactlyOneOf(path.MatchRoot("policy_id"), path.MatchRoot("policy_name")),
},
// Validators: []validator.Int64{
// int64validator.NullIfAttributeIsSet(path.MatchRoot("policy_name")),
// // int64validator.ExactlyOneOf(path.MatchRoot("policy_id"), path.MatchRoot("policy_name")),
// },
},
},
"policy_name": superschema.SuperStringAttribute{
Expand All @@ -166,9 +167,9 @@ func backupSchema(_ context.Context) superschema.Schema {
},
Resource: &schemaR.StringAttribute{
Optional: true,
Validators: []validator.String{
stringvalidator.ExactlyOneOf(path.MatchRoot("policy_id"), path.MatchRoot("policy_name")),
},
// Validators: []validator.String{
// stringvalidator.ExactlyOneOf(path.MatchRoot("policy_id"), path.MatchRoot("policy_name")),
// },
},
},
"enabled": superschema.SuperBoolAttribute{
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/backup/backup_schema_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package netbackup_test
package backup_test

import (
"context"
Expand Down
43 changes: 39 additions & 4 deletions internal/provider/backup/backup_types.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,42 @@
package netbackup
package backup

import "github.com/hashicorp/terraform-plugin-framework/types"
import (
"context"

type BackupModel struct {
ID types.String `tfsdk:"id"`
"github.com/hashicorp/terraform-plugin-framework/diag"

supertypes "github.com/FrangipaneTeam/terraform-plugin-framework-supertypes"

"github.com/orange-cloudavenue/terraform-provider-cloudavenue/pkg/utils"
)

type backupModel struct {
ID supertypes.StringValue `tfsdk:"id"`
Policies supertypes.SetNestedValue `tfsdk:"policies"`
TargetID supertypes.StringValue `tfsdk:"target_id"`
TargetName supertypes.StringValue `tfsdk:"target_name"`
Type supertypes.StringValue `tfsdk:"type"`
}

// * Policies.
type backupModelPolicies []backupModelPolicy

// * Policies.
type backupModelPolicy struct {
Enabled supertypes.BoolValue `tfsdk:"enabled"`
PolicyID supertypes.Int64Value `tfsdk:"policy_id"`
PolicyName supertypes.StringValue `tfsdk:"policy_name"`
}

func (rm *backupModel) Copy() *backupModel {
x := &backupModel{}
utils.ModelCopy(rm, x)
return x
}

// GetPolicies returns the value of the Policies field.
func (rm *backupModel) GetPolicies(ctx context.Context) (values backupModelPolicies, diags diag.Diagnostics) {
values = make(backupModelPolicies, 0)
d := rm.Policies.Get(ctx, &values, false)
return values, d
}
4 changes: 2 additions & 2 deletions internal/provider/backup/base.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package netbackup
package backup

const (
categoryName = "netbackup"
categoryName = "backup"
)

0 comments on commit 13aa297

Please sign in to comment.