Skip to content

Commit

Permalink
Merge pull request #59 from Juniper/data-source-node
Browse files Browse the repository at this point in the history
Data source `apstra_datacenter_blueprint_system_nodes`
  • Loading branch information
chrismarget-j authored May 4, 2023
2 parents 7f1719d + 9cc82e9 commit be21191
Show file tree
Hide file tree
Showing 16 changed files with 954 additions and 49 deletions.
79 changes: 46 additions & 33 deletions apstra/blueprint/device_allocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,10 @@ func (o *DeviceAllocation) validateInterfaceMapId(ctx context.Context, client *a
} `json:"items"`
}

query := client.NewQuery(apstra.ObjectId(o.BlueprintId.ValueString())).
SetType(apstra.BlueprintTypeStaging).
SetContext(ctx).
query := new(apstra.PathQuery).
SetClient(client).
SetBlueprintId(apstra.ObjectId(o.BlueprintId.ValueString())).
SetBlueprintType(apstra.BlueprintTypeStaging).
Node([]apstra.QEEAttribute{
{"type", apstra.QEStringVal("system")},
{"id", apstra.QEStringVal(o.NodeId.ValueString())},
Expand All @@ -123,7 +124,7 @@ func (o *DeviceAllocation) validateInterfaceMapId(ctx context.Context, client *a
{"id", apstra.QEStringVal(o.DeviceProfileNodeId.ValueString())},
})

err := query.Do(&result)
err := query.Do(ctx, &result)
if err != nil {
if utils.IsApstra404(err) {
o.BlueprintId = types.StringNull()
Expand Down Expand Up @@ -151,9 +152,10 @@ func (o *DeviceAllocation) populateInterfaceMapIdFromNodeIdAndDeviceProfileNodeI
} `json:"items"`
}

query := client.NewQuery(apstra.ObjectId(o.BlueprintId.ValueString())).
SetContext(ctx).
SetType(apstra.BlueprintTypeStaging).
query := new(apstra.PathQuery).
SetClient(client).
SetBlueprintId(apstra.ObjectId(o.BlueprintId.ValueString())).
SetBlueprintType(apstra.BlueprintTypeStaging).
Node([]apstra.QEEAttribute{
{"type", apstra.QEStringVal("system")},
{"id", apstra.QEStringVal(o.NodeId.ValueString())},
Expand All @@ -173,7 +175,7 @@ func (o *DeviceAllocation) populateInterfaceMapIdFromNodeIdAndDeviceProfileNodeI
{"id", apstra.QEStringVal(o.DeviceProfileNodeId.ValueString())},
})

err := query.Do(&result)
err := query.Do(ctx, &result)
if err != nil {
if utils.IsApstra404(err) {
o.BlueprintId = types.StringNull()
Expand Down Expand Up @@ -210,16 +212,17 @@ func (o *DeviceAllocation) nodeIdFromNodeName(ctx context.Context, client *apstr
} `json:"items"`
}

query := client.NewQuery(apstra.ObjectId(o.BlueprintId.ValueString())).
SetType(apstra.BlueprintTypeStaging).
SetContext(ctx).
query := new(apstra.PathQuery).
SetClient(client).
SetBlueprintId(apstra.ObjectId(o.BlueprintId.ValueString())).
SetBlueprintType(apstra.BlueprintTypeStaging).
Node([]apstra.QEEAttribute{
{"type", apstra.QEStringVal("system")},
{"label", apstra.QEStringVal(o.NodeName.ValueString())},
{"name", apstra.QEStringVal("n_system")},
})

err := query.Do(&result)
err := query.Do(ctx, &result)
if err != nil {
diags.AddError("error running system node query", err.Error())
return
Expand Down Expand Up @@ -375,16 +378,17 @@ func (o *DeviceAllocation) ReadSystemNode(ctx context.Context, client *apstra.Cl
} `json:"items"`
}

query := client.NewQuery(apstra.ObjectId(o.BlueprintId.ValueString())).
SetContext(ctx).
SetType(apstra.BlueprintTypeStaging).
query := new(apstra.PathQuery).
SetClient(client).
SetBlueprintId(apstra.ObjectId(o.BlueprintId.ValueString())).
SetBlueprintType(apstra.BlueprintTypeStaging).
Node([]apstra.QEEAttribute{
{"type", apstra.QEStringVal("system")},
{"id", apstra.QEStringVal(o.NodeId.ValueString())},
{"name", apstra.QEStringVal("n_system")},
})

err := query.Do(&result)
err := query.Do(ctx, &result)
if err != nil {
if utils.IsApstra404(err) {
o.BlueprintId = types.StringNull()
Expand Down Expand Up @@ -421,8 +425,10 @@ func (o *DeviceAllocation) GetCurrentInterfaceMapId(ctx context.Context, client
} `json:"items"`
}

err := client.NewQuery(apstra.ObjectId(o.BlueprintId.ValueString())).
SetContext(ctx).
query := new(apstra.PathQuery).
SetClient(client).
SetBlueprintId(apstra.ObjectId(o.BlueprintId.ValueString())).
SetBlueprintType(apstra.BlueprintTypeStaging).
Node([]apstra.QEEAttribute{
{"type", apstra.QEStringVal("system")},
{"id", apstra.QEStringVal(o.NodeId.ValueString())},
Expand All @@ -431,8 +437,9 @@ func (o *DeviceAllocation) GetCurrentInterfaceMapId(ctx context.Context, client
Node([]apstra.QEEAttribute{
{"type", apstra.QEStringVal("interface_map")},
{"name", apstra.QEStringVal("n_interface_map")},
}).
Do(&result)
})

err := query.Do(ctx, &result)
if err != nil {
if utils.IsApstra404(err) {
o.BlueprintId = types.StringNull()
Expand Down Expand Up @@ -466,8 +473,10 @@ func (o *DeviceAllocation) GetCurrentDeviceProfileId(ctx context.Context, client
} `json:"items"`
}

query := client.NewQuery(apstra.ObjectId(o.BlueprintId.ValueString())).
SetContext(ctx).
query := new(apstra.PathQuery).
SetClient(client).
SetBlueprintId(apstra.ObjectId(o.BlueprintId.ValueString())).
SetBlueprintType(apstra.BlueprintTypeStaging).
Node([]apstra.QEEAttribute{
{"type", apstra.QEStringVal("system")},
{"id", apstra.QEStringVal(o.NodeId.ValueString())},
Expand All @@ -484,7 +493,7 @@ func (o *DeviceAllocation) GetCurrentDeviceProfileId(ctx context.Context, client
{"name", apstra.QEStringVal("n_device_profile")},
})

err := query.Do(&result)
err := query.Do(ctx, &result)
if err != nil {
if utils.IsApstra404(err) {
o.BlueprintId = types.StringNull()
Expand Down Expand Up @@ -518,9 +527,10 @@ func (o *DeviceAllocation) deviceProfileNodeIdFromInterfaceMapCatalogId(ctx cont
} `json:"items"`
}

query := client.NewQuery(apstra.ObjectId(o.BlueprintId.ValueString())).
SetType(apstra.BlueprintTypeStaging).
SetContext(ctx).
query := new(apstra.PathQuery).
SetClient(client).
SetBlueprintId(apstra.ObjectId(o.BlueprintId.ValueString())).
SetBlueprintType(apstra.BlueprintTypeStaging).
Node([]apstra.QEEAttribute{
{"type", apstra.QEStringVal("interface_map")},
{"id", apstra.QEStringVal(o.InterfaceMapCatalogId.ValueString())},
Expand All @@ -531,7 +541,7 @@ func (o *DeviceAllocation) deviceProfileNodeIdFromInterfaceMapCatalogId(ctx cont
{"name", apstra.QEStringVal("n_device_profile")},
})

err := query.Do(&response)
err := query.Do(ctx, &response)

if err != nil {
if utils.IsApstra404(err) {
Expand All @@ -544,11 +554,13 @@ func (o *DeviceAllocation) deviceProfileNodeIdFromInterfaceMapCatalogId(ctx cont

switch len(response.Items) {
case 0:
diags.AddError("no results when querying for Device Profile", fmt.Sprintf("query string %q", query.String()))
diags.AddError("no results when querying for Device Profile",
fmt.Sprintf("query string %q", query.String()))
case 1:
o.DeviceProfileNodeId = types.StringValue(response.Items[0].DeviceProfile.Id)
default:
diags.AddError("multiple matches when querying for Device Profile", fmt.Sprintf("query string %q", query.String()))
diags.AddError("multiple matches when querying for Device Profile",
fmt.Sprintf("query string %q", query.String()))
}
}

Expand All @@ -568,9 +580,10 @@ func (o *DeviceAllocation) deviceProfileNodeIdFromDeviceKey(ctx context.Context,
return
}

query := client.NewQuery(apstra.ObjectId(o.BlueprintId.ValueString())).
SetContext(ctx).
SetType(apstra.BlueprintTypeStaging).
query := new(apstra.PathQuery).
SetClient(client).
SetBlueprintId(apstra.ObjectId(o.BlueprintId.ValueString())).
SetBlueprintType(apstra.BlueprintTypeStaging).
Node([]apstra.QEEAttribute{
{"type", apstra.QEStringVal("device_profile")},
{"device_profile_id", apstra.QEStringVal(si.Facts.AosHclModel.String())},
Expand All @@ -585,7 +598,7 @@ func (o *DeviceAllocation) deviceProfileNodeIdFromDeviceKey(ctx context.Context,
} `json:"items"`
}

err := query.Do(&result)
err := query.Do(ctx, &result)
if err != nil {
if utils.IsApstra404(err) {
o.BlueprintId = types.StringNull()
Expand Down
113 changes: 113 additions & 0 deletions apstra/blueprint/node_system.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package blueprint

import (
"context"
"fmt"
"github.com/Juniper/apstra-go-sdk/apstra"
"github.com/hashicorp/terraform-plugin-framework/attr"
dataSourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
"terraform-provider-apstra/apstra/utils"
)

type NodeTypeSystem struct {
BlueprintId types.String `tfsdk:"blueprint_id"`
Id types.String `tfsdk:"id"`
Attributes types.Object `tfsdk:"attributes"`
}

func (o NodeTypeSystem) DataSourceAttributes() map[string]dataSourceSchema.Attribute {
return map[string]dataSourceSchema.Attribute{
"blueprint_id": dataSourceSchema.StringAttribute{
MarkdownDescription: "Apstra Blueprint ID",
Required: true,
},
"id": dataSourceSchema.StringAttribute{
MarkdownDescription: "Apstra Graph DB node `ID`",
Required: true,
},
"attributes": dataSourceSchema.SingleNestedAttribute{
MarkdownDescription: "Attributes of a `system` Graph DB node.",
Computed: true,
Attributes: NodeTypeSystemAttributes{}.DataSourceAttributes(),
},
}
}

func (o *NodeTypeSystem) ReadFromApi(ctx context.Context, client *apstra.Client, diags *diag.Diagnostics) {
type node struct {
Id string `json:"id"`
Hostname string `json:"hostname"`
Label string `json:"label"`
Role string `json:"role"`
SystemId string `json:"system_id"`
SystemType string `json:"system_type"`
}
nodeResponse := &struct {
Nodes map[string]node `json:"nodes"`
}{}

err := client.GetNodes(ctx, apstra.ObjectId(o.BlueprintId.ValueString()), apstra.NodeTypeSystem, nodeResponse)
if err != nil {
diags.AddError("error fetching blueprint nodes", err.Error())
return
}

// pick out the desired node from the node slice in the response object
desiredNode := new(node)
for _, n := range nodeResponse.Nodes {
if n.Id == o.Id.ValueString() {
desiredNode = &n
break
}
}

if desiredNode == nil {
diags.AddError("node not found",
fmt.Sprintf("node %q not found in blueprint %q",
o.Id.ValueString(), o.BlueprintId.ValueString()))
return
}

tagResponse := &struct {
Items []struct {
Tag struct {
Label string `json:"label"`
} `json:"n_tag"`
} `json:"items"`
}{}

err = new(apstra.PathQuery).
SetClient(client).
SetBlueprintId(apstra.ObjectId(o.BlueprintId.ValueString())).
SetBlueprintType(apstra.BlueprintTypeStaging).
Node([]apstra.QEEAttribute{{Key: "id", Value: apstra.QEStringVal(desiredNode.Id)}}).
In([]apstra.QEEAttribute{{Key: "type", Value: apstra.QEStringVal("tag")}}).
Node([]apstra.QEEAttribute{
{Key: "type", Value: apstra.QEStringVal("tag")},
{Key: "name", Value: apstra.QEStringVal("n_tag")},
}).
Do(ctx, tagResponse)
if err != nil {
diags.AddError(
fmt.Sprintf("error querying graph db tags for node %q", desiredNode.Id),
err.Error())
return
}

tags := make([]attr.Value, len(tagResponse.Items))
for i := range tagResponse.Items {
tags[i] = types.StringValue(tagResponse.Items[i].Tag.Label)
}

o.Attributes = types.ObjectValueMust(NodeTypeSystemAttributes{}.AttrTypes(), map[string]attr.Value{
"id": utils.StringValueOrNull(ctx, desiredNode.Id, diags),
"hostname": utils.StringValueOrNull(ctx, desiredNode.Hostname, diags),
"label": utils.StringValueOrNull(ctx, desiredNode.Label, diags),
"role": utils.StringValueOrNull(ctx, desiredNode.Role, diags),
"system_id": utils.StringValueOrNull(ctx, desiredNode.SystemId, diags),
"system_type": utils.StringValueOrNull(ctx, desiredNode.SystemType, diags),
"tag_ids": utils.SetValueOrNull(ctx, types.StringType, tags, diags),
})
}
Loading

0 comments on commit be21191

Please sign in to comment.