diff --git a/docs/resources/vpcs.md b/docs/resources/vpcs.md index bb2bae6..29717ac 100644 --- a/docs/resources/vpcs.md +++ b/docs/resources/vpcs.md @@ -29,7 +29,29 @@ description: |- - `created` (String) - `error_message` (String) - `id` (Number) The ID of this resource. +- `peering_connections` (Attributes List) (see [below for nested schema](#nestedatt--peering_connections)) - `project_id` (String) - `provisioned_id` (String) - `status` (String) - `updated` (String) + + +### Nested Schema for `peering_connections` + +Read-Only: + +- `error_message` (String) +- `id` (Number) +- `peer_vpc` (Object) (see [below for nested schema](#nestedatt--peering_connections--peer_vpc)) +- `status` (String) +- `vpc_id` (String) + + +### Nested Schema for `peering_connections.peer_vpc` + +Read-Only: + +- `account_id` (String) +- `cidr` (String) +- `id` (String) +- `region_code` (String) diff --git a/internal/client/queries/create_vpc.graphql b/internal/client/queries/create_vpc.graphql index 0b8b36b..0a85839 100644 --- a/internal/client/queries/create_vpc.graphql +++ b/internal/client/queries/create_vpc.graphql @@ -12,6 +12,18 @@ mutation CreateVPC($projectId: ID!, $name: String!, $cidr: String!, $regionCode: name created updated + peeringConnections { + id + vpcId + peerVpc { + id + accountId + regionCode + cidr + } + errorMessage + status + } errorMessage status regionCode diff --git a/internal/client/queries/vpc_by_id.graphql b/internal/client/queries/vpc_by_id.graphql index d6d923c..f1f2fce 100644 --- a/internal/client/queries/vpc_by_id.graphql +++ b/internal/client/queries/vpc_by_id.graphql @@ -6,17 +6,18 @@ name created updated - # peeringConnections { - # vpcId - # peerVpc { - # id - # accountId - # regionCode - # cidr - # } - # errorMessage - # status - # } + peeringConnections { + id + vpcId + peerVpc { + id + accountId + regionCode + cidr + } + errorMessage + status + } errorMessage status regionCode diff --git a/internal/client/queries/vpc_by_name.graphql b/internal/client/queries/vpc_by_name.graphql index e81480f..a3cf38f 100644 --- a/internal/client/queries/vpc_by_name.graphql +++ b/internal/client/queries/vpc_by_name.graphql @@ -9,17 +9,18 @@ query GetVPCByName($projectId: ID!, $name: String!) { name created updated - # peeringConnections { - # vpcId - # peerVpc { - # id - # accountId - # regionCode - # cidr - # } - # errorMessage - # status - # } + peeringConnections { + id + vpcId + peerVpc { + id + accountId + regionCode + cidr + } + errorMessage + status + } errorMessage status regionCode diff --git a/internal/client/queries/vpcs.graphql b/internal/client/queries/vpcs.graphql index f804d44..5981e14 100644 --- a/internal/client/queries/vpcs.graphql +++ b/internal/client/queries/vpcs.graphql @@ -7,6 +7,7 @@ created updated peeringConnections { + id vpcId peerVpc { id diff --git a/internal/provider/vpc_resource.go b/internal/provider/vpc_resource.go index d0102be..2c8d25a 100644 --- a/internal/provider/vpc_resource.go +++ b/internal/provider/vpc_resource.go @@ -43,46 +43,72 @@ type vpcResource struct { client *tsClient.Client } -// vpcResourceModel maps vpcs schema data. type vpcResourceModel struct { - ID types.Int64 `tfsdk:"id"` - ProvisionedID types.String `tfsdk:"provisioned_id"` - ProjectID types.String `tfsdk:"project_id"` - CIDR types.String `tfsdk:"cidr"` - Name types.String `tfsdk:"name"` - RegionCode types.String `tfsdk:"region_code"` - Status types.String `tfsdk:"status"` - ErrorMessage types.String `tfsdk:"error_message"` - Created types.String `tfsdk:"created"` - Updated types.String `tfsdk:"updated"` - // PeeringConnections types.List `tfsdk:"peering_connections"` + ID types.Int64 `tfsdk:"id"` + ProvisionedID types.String `tfsdk:"provisioned_id"` + ProjectID types.String `tfsdk:"project_id"` + CIDR types.String `tfsdk:"cidr"` + Name types.String `tfsdk:"name"` + RegionCode types.String `tfsdk:"region_code"` + Status types.String `tfsdk:"status"` + ErrorMessage types.String `tfsdk:"error_message"` + Created types.String `tfsdk:"created"` + Updated types.String `tfsdk:"updated"` + PeeringConnections types.List `tfsdk:"peering_connections"` } -// type peeringConnectionResourceModel struct { -// ID types.Int64 `tfsdk:"id"` -// VpcID types.Int64 `tfsdk:"vpc_id"` -// Status types.String `tfsdk:"status"` -// ErrorMessage types.String `tfsdk:"error_message"` -// PeerVpcs types.List `tfsdk:"peer_vpc"` -// } +type peeringConnectionResourceModel struct { + ID types.Int64 `tfsdk:"id"` + VpcID types.String `tfsdk:"vpc_id"` + Status types.String `tfsdk:"status"` + ErrorMessage types.String `tfsdk:"error_message"` + PeerVpcs types.Object `tfsdk:"peer_vpc"` +} + +type peerVpcModel struct { + ID types.String `tfsdk:"id"` + CIDR types.String `tfsdk:"cidr"` + AccountID types.String `tfsdk:"account_id"` + RegionCode types.String `tfsdk:"region_code"` +} var ( - PeerVpcType = types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "id": types.Int64Type, - "cidr": types.StringType, - "account_id": types.StringType, - "region_code": types.StringType, - }, + PeerVpcType = map[string]attr.Type{ + "id": types.StringType, + "cidr": types.StringType, + "account_id": types.StringType, + "region_code": types.StringType, } PeeringConnectionsType = types.ObjectType{ AttrTypes: map[string]attr.Type{ "id": types.Int64Type, - "vpc_id": types.Int64Type, + "vpc_id": types.StringType, "status": types.StringType, "error_message": types.StringType, - "peer_vpc": types.ListType{ElemType: PeerVpcType}, + "peer_vpc": types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "id": types.StringType, + "cidr": types.StringType, + "account_id": types.StringType, + "region_code": types.StringType, + }, + }, + }, + } + + PeeringConnectionType = map[string]attr.Type{ + "id": types.Int64Type, + "vpc_id": types.StringType, + "status": types.StringType, + "error_message": types.StringType, + "peer_vpc": types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "id": types.StringType, + "cidr": types.StringType, + "account_id": types.StringType, + "region_code": types.StringType, + }, }, } ) @@ -94,17 +120,16 @@ func (r *vpcResource) Metadata(_ context.Context, req resource.MetadataRequest, // Read refreshes the Terraform state with the latest data. func (r *vpcResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - tflog.Trace(ctx, "VpcResource.Read") var state vpcResourceModel - var vpc *tsClient.VPC - var err error - // Read Terraform prior state plan into the model - resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) if resp.Diagnostics.HasError() { return } + var vpc *tsClient.VPC + var err error + if !state.Name.IsNull() { tflog.Info(ctx, "Getting VPC by name: "+state.Name.ValueString()) vpc, err = r.client.GetVPCByName(ctx, state.Name.ValueString()) @@ -125,16 +150,17 @@ func (r *vpcResource) Read(ctx context.Context, req resource.ReadRequest, resp * state.ProjectID = types.StringValue(vpc.ProjectID) state.CIDR = types.StringValue(vpc.CIDR) state.RegionCode = types.StringValue(vpc.RegionCode) - resourceModel := vpcToResource(resp.Diagnostics, vpc, state) + + model := vpcToResource(ctx, resp.Diagnostics, vpc, state) // Save updated plan into Terraform state - resp.Diagnostics.Append(resp.State.Set(ctx, resourceModel)...) + resp.Diagnostics.Append(resp.State.Set(ctx, model)...) if resp.Diagnostics.HasError() { tflog.Error(ctx, fmt.Sprintf("error updating terraform state %v", resp.Diagnostics.Errors())) return } } -func vpcToResource(_ diag.Diagnostics, s *tsClient.VPC, state vpcResourceModel) vpcResourceModel { +func vpcToResource(ctx context.Context, diag diag.Diagnostics, s *tsClient.VPC, state vpcResourceModel) vpcResourceModel { model := vpcResourceModel{ ID: state.ID, ProjectID: state.ProjectID, @@ -146,40 +172,42 @@ func vpcToResource(_ diag.Diagnostics, s *tsClient.VPC, state vpcResourceModel) Status: types.StringValue(s.Status), ErrorMessage: types.StringValue(s.ErrorMessage), Updated: types.StringValue(s.Updated), - // PeeringConnections: types.ListUnknown(PeeringConnectionsType), } - // for _, peeringConn := range vpc.PeeringConnections { - // peeringConnID, err := strconv.ParseInt(peeringConn.ID, 10, 64) - // if err != nil { - // resp.Diagnostics.AddError("Unable to Convert Vpc ID", err.Error()) - // return - // } - // peeringConnVpcID, err := strconv.ParseInt(peeringConn.VpcID, 10, 64) - // if err != nil { - // resp.Diagnostics.AddError("Unable to Convert Vpc ID", err.Error()) - // return - // } - // peerConn := peeringConnectionModel{ - // ID: types.Int64Value(peeringConnID), - // VpcID: types.Int64Value(peeringConnVpcID), - // Status: types.StringValue(peeringConn.Status), - // ErrorMessage: types.StringValue(peeringConn.ErrorMessage), - // } - // for _, peerVpc := range peeringConn.PeerVpcs { - // peerVpcId, err := strconv.ParseInt(peerVpc.ID, 10, 64) - // if err != nil { - // resp.Diagnostics.AddError("Unable to Convert Vpc ID", err.Error()) - // return - // } - // peerConn.PeerVpcs = append(peerConn.PeerVpcs, &peerVpcModel{ - // ID: types.Int64Value(peerVpcId), - // AccountID: types.StringValue(peerVpc.AccountID), - // CIDR: types.StringValue(peerVpc.CIDR), - // RegionCode: types.StringValue(peerVpc.RegionCode), - // }) - // } - // vpcState.PeeringConnections = append(vpcState.PeeringConnections, peerConn) - // } + + pcmObjs := make([]attr.Value, 0, len(s.PeeringConnections)) + for _, pc := range s.PeeringConnections { + var pcm peeringConnectionResourceModel + pcm.ErrorMessage = types.StringValue(pc.ErrorMessage) + peeringConnID, err := strconv.ParseInt(pc.ID, 10, 64) + if err != nil { + diag.AddError("Parse Error", "could not parse peering connection ID") + } + pcm.ID = types.Int64Value(peeringConnID) + pcm.VpcID = types.StringValue(pc.VPCID) + pcm.Status = types.StringValue(pc.Status) + if pc.ErrorMessage != "" { + pcm.ErrorMessage = types.StringValue(pc.ErrorMessage) + } + + peerVpcs, errDiag := types.ObjectValueFrom(ctx, PeerVpcType, peerVpcModel{ + ID: types.StringValue(pc.PeerVPC.ID), + AccountID: types.StringValue(pc.PeerVPC.AccountID), + CIDR: types.StringValue(pc.PeerVPC.CIDR), + RegionCode: types.StringValue(pc.PeerVPC.RegionCode), + }) + diag.Append(errDiag...) + pcm.PeerVpcs = peerVpcs + pcmObj, d := types.ObjectValueFrom(ctx, PeeringConnectionType, pcm) + diag.Append(d...) + pcmObjs = append(pcmObjs, pcmObj) + + } + pcms, err := types.ListValue(PeeringConnectionsType, pcmObjs) + if err != nil { + diag.AddError("Parse Error", "could not parse peering connection ID") + } + model.PeeringConnections = pcms + return model } @@ -191,14 +219,14 @@ func (r *vpcResource) Create(ctx context.Context, req resource.CreateRequest, re // Read Terraform plan data into the model resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) - if plan.CIDR.IsNull() { - resp.Diagnostics.AddError(ErrVPCCreate, "CIDR is required") - return - } if plan.RegionCode.IsNull() { resp.Diagnostics.AddError(ErrVPCCreate, "Region code is required") return } + if plan.CIDR.IsNull() { + resp.Diagnostics.AddError(ErrVPCCreate, "CIDR is required") + return + } vpc, err := r.client.CreateVPC(ctx, plan.Name.ValueString(), plan.CIDR.ValueString(), plan.RegionCode.ValueString()) if err != nil { resp.Diagnostics.AddError( @@ -216,10 +244,10 @@ func (r *vpcResource) Create(ctx context.Context, req resource.CreateRequest, re plan.ProjectID = types.StringValue(vpc.ProjectID) plan.CIDR = types.StringValue(vpc.CIDR) plan.RegionCode = types.StringValue(vpc.RegionCode) - resourceModel := vpcToResource(resp.Diagnostics, vpc, plan) + model := vpcToResource(ctx, resp.Diagnostics, vpc, plan) // Set state - resp.Diagnostics.Append(resp.State.Set(ctx, resourceModel)...) + resp.Diagnostics.Append(resp.State.Set(ctx, model)...) if resp.Diagnostics.HasError() { return } @@ -289,18 +317,14 @@ func (r *vpcResource) Configure(ctx context.Context, req resource.ConfigureReque if req.ProviderData == nil { return } - client, ok := req.ProviderData.(*tsClient.Client) - if !ok { resp.Diagnostics.AddError( "Unexpected Resource Configure Type", fmt.Sprintf("Expected *tsClient.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) - return } - r.client = client } @@ -368,45 +392,34 @@ func (r *vpcResource) Schema(_ context.Context, _ resource.SchemaRequest, resp * stringplanmodifier.UseStateForUnknown(), }, }, - // "peering_connections": schema.ListNestedAttribute{ - // Optional: true, - // Computed: true, - // NestedObject: schema.NestedAttributeObject{ - // Attributes: map[string]schema.Attribute{ - // "id": schema.Int64Attribute{ - // Computed: true, - // }, - // "vpc_id": schema.Int64Attribute{ - // Computed: true, - // }, - // "status": schema.StringAttribute{ - // Computed: true, - // }, - // "error_message": schema.StringAttribute{ - // Computed: true, - // }, - // "peer_vpc": schema.ListNestedAttribute{ - // Computed: true, - // NestedObject: schema.NestedAttributeObject{ - // Attributes: map[string]schema.Attribute{ - // "id": schema.Int64Attribute{ - // Computed: true, - // }, - // "cidr": schema.StringAttribute{ - // Computed: true, - // }, - // "region_code": schema.StringAttribute{ - // Computed: true, - // }, - // "account_id": schema.StringAttribute{ - // Computed: true, - // }, - // }, - // }, - // }, - // }, - // }, - // }, + "peering_connections": schema.ListNestedAttribute{ + Computed: true, + NestedObject: schema.NestedAttributeObject{ + Attributes: map[string]schema.Attribute{ + "id": schema.Int64Attribute{ + Computed: true, + }, + "vpc_id": schema.StringAttribute{ + Computed: true, + }, + "status": schema.StringAttribute{ + Computed: true, + }, + "error_message": schema.StringAttribute{ + Computed: true, + }, + "peer_vpc": schema.ObjectAttribute{ + Computed: true, + AttributeTypes: map[string]attr.Type{ + "id": types.StringType, + "cidr": types.StringType, + "account_id": types.StringType, + "region_code": types.StringType, + }, + }, + }, + }, + }, }, } } diff --git a/internal/provider/vpcs_data_source.go b/internal/provider/vpcs_data_source.go index f136566..3ebcdf0 100644 --- a/internal/provider/vpcs_data_source.go +++ b/internal/provider/vpcs_data_source.go @@ -127,29 +127,27 @@ func (d *vpcsDataSource) Read(ctx context.Context, _ datasource.ReadRequest, res Created: types.StringValue(vpc.Created), } - if len(vpc.PeeringConnections) > 0 { - var pcms []peeringConnectionDSModel - for _, pc := range vpc.PeeringConnections { - var pcm peeringConnectionDSModel - if pc.ErrorMessage != "" { - pcm.ErrorMessage = types.StringValue(pc.ErrorMessage) - } - pcm.VpcID = types.StringValue(pc.VPCID) - pcm.Status = types.StringValue(pc.Status) - peerVpcs, errDiag := types.ObjectValueFrom(ctx, PeerVpcDSType, peerVpcDSModel{ - ID: types.StringValue(pc.PeerVPC.ID), - AccountID: types.StringValue(pc.PeerVPC.AccountID), - CIDR: types.StringValue(pc.PeerVPC.CIDR), - RegionCode: types.StringValue(pc.PeerVPC.RegionCode), - }) - if errDiag.HasError() { - resp.Diagnostics.Append(errDiag...) - } - pcm.PeerVpcs = peerVpcs - pcms = append(pcms, pcm) + var pcms []peeringConnectionDSModel + for _, pc := range vpc.PeeringConnections { + var pcm peeringConnectionDSModel + if pc.ErrorMessage != "" { + pcm.ErrorMessage = types.StringValue(pc.ErrorMessage) } - vpcState.PeeringConnections = pcms + pcm.VpcID = types.StringValue(pc.VPCID) + pcm.Status = types.StringValue(pc.Status) + peerVpcs, errDiag := types.ObjectValueFrom(ctx, PeerVpcDSType, peerVpcDSModel{ + ID: types.StringValue(pc.PeerVPC.ID), + AccountID: types.StringValue(pc.PeerVPC.AccountID), + CIDR: types.StringValue(pc.PeerVPC.CIDR), + RegionCode: types.StringValue(pc.PeerVPC.RegionCode), + }) + if errDiag.HasError() { + resp.Diagnostics.Append(errDiag...) + } + pcm.PeerVpcs = peerVpcs + pcms = append(pcms, pcm) } + vpcState.PeeringConnections = pcms state.Vpcs = append(state.Vpcs, vpcState) } // this is a placeholder, required by terraform to run test suite