Skip to content

Commit ce80698

Browse files
authored
Add cloudspace, spotnodepool data sources along with allocation and bid status attributes (#7)
* Add bidstatus, allocation info and other computed attributes * Add cloudspace, spotnodepool data source * The data sources now accepts name as id * Rename `rxtspot_token` to `token` in provider config * Dedupe code for transformation
1 parent b977aac commit ce80698

22 files changed

+3187
-201
lines changed

Diff for: docs/data-sources/cloudspace.md

+30-2
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,44 @@ output "csphase" {
2828

2929
### Required
3030

31-
- `id` (String) ID of the cloudspace
31+
- `id` (String) ID of the cloudspace, same as cloudspace name.
32+
33+
### Optional
34+
35+
- `preemption_webhook` (String) Webhook URL for preemption notifications.
3236

3337
### Read-Only
3438

3539
- `api_server_endpoint` (String) Kubernetes api server URL
40+
- `bids` (Attributes Set) (see [below for nested schema](#nestedatt--bids))
41+
- `cloudspace_name` (String) Name of the cloudspace
42+
- `first_ready_timestamp` (String) The time when the cloudspace was first ready.
43+
- `hacontrol_plane` (Boolean) High Availability Kubernetes (replicated control plane for redundancy). This is a critical feature for production workloads.
3644
- `health` (String) Health indicates if CloudSpace has a working APIServer and available nodes
3745
- `kubeconfig` (String, Deprecated) Kubeconfig blob
38-
- `name` (String) Name of the cloudspace
46+
- `name` (String, Deprecated) Name of the cloudspace
47+
- `pending_allocations` (Attributes Set) (see [below for nested schema](#nestedatt--pending_allocations))
3948
- `phase` (String) Phase of the cloudspace
4049
- `reason` (String) Reason contains the reason why the CloudSpace is in a certain phase.
4150
- `region` (String) The region where the cloudspace resides.
51+
- `spotnodepool_ids` (List of String) IDs of the spotnodepools associated with the cloudspace.
4252
- `token` (String) Token to use for authentication to kubernetes api server
4353
- `user` (String) Name of the user to use for authentication to kubernetes api server
54+
55+
<a id="nestedatt--bids"></a>
56+
### Nested Schema for `bids`
57+
58+
Read-Only:
59+
60+
- `bid_name` (String)
61+
- `won_count` (Number)
62+
63+
64+
<a id="nestedatt--pending_allocations"></a>
65+
### Nested Schema for `pending_allocations`
66+
67+
Read-Only:
68+
69+
- `bid_name` (String)
70+
- `count` (Number)
71+
- `server_class` (String)

Diff for: docs/data-sources/kubeconfig.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ resource "local_file" "kubeconfig" {
7070

7171
### Required
7272

73-
- `id` (String) ID of the cloudspace
73+
- `id` (String) ID of the cloudspace, same as cloudspace name.
7474

7575
### Read-Only
7676

Diff for: docs/data-sources/spotnodepool.md

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "spot_spotnodepool Data Source - terraform-provider-spot"
4+
subcategory: ""
5+
description: |-
6+
7+
---
8+
9+
# spot_spotnodepool (Data Source)
10+
11+
12+
13+
14+
15+
<!-- schema generated by tfplugindocs -->
16+
## Schema
17+
18+
### Required
19+
20+
- `id` (String) ID of the spotnodepool
21+
22+
### Read-Only
23+
24+
- `autoscaling` (Attributes) (see [below for nested schema](#nestedatt--autoscaling))
25+
- `bid_price` (Number) The bid price for the server in USD
26+
- `bid_status` (String) Status of the bid associated with this spotnodepool.
27+
- `cloudspace_name` (String) The name of the cloudspace
28+
- `desired_server_count` (Number) The desired number of servers in the node pool.
29+
- `server_class` (String) The class of servers to use for the node pool.
30+
- `won_count` (Number) Number of won bids.
31+
32+
<a id="nestedatt--autoscaling"></a>
33+
### Nested Schema for `autoscaling`
34+
35+
Read-Only:
36+
37+
- `max_nodes` (Number) The maximum number of nodes in the node pool.
38+
- `min_nodes` (Number) The minimum number of nodes in the node pool.

Diff for: docs/index.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ terraform {
4141
4242
provider "spot" {
4343
# overrides environment variables
44-
rxtspot_token = "<token>"
44+
token = "<rxtspot_token>"
4545
}
4646
```
4747

@@ -50,7 +50,7 @@ provider "spot" {
5050

5151
### Optional
5252

53-
- `rxtspot_token` (String, Sensitive) API token used to authenticate against Spot backend
53+
- `token` (String, Sensitive) API token used to authenticate against Spot backend
5454

5555
## Create Your First Cloudspace
5656

Diff for: docs/resources/cloudspace.md

+23-1
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,31 @@ resource "spot_cloudspace" "example" {
3737

3838
### Read-Only
3939

40-
- `id` (String) The id of the cloudspace.
40+
- `bids` (Attributes Set) (see [below for nested schema](#nestedatt--bids))
41+
- `first_ready_timestamp` (String) The time when the cloudspace was first ready.
42+
- `id` (String) The id of the cloudspace
4143
- `last_updated` (String) The last time the cloudspace was updated.
44+
- `pending_allocations` (Attributes Set) (see [below for nested schema](#nestedatt--pending_allocations))
4245
- `resource_version` (String) The version of the resource known to local state. This is used to determine if the resource is modified outside of terraform.
46+
- `spotnodepool_ids` (List of String) IDs of the spotnodepools associated with the cloudspace.
47+
48+
<a id="nestedatt--bids"></a>
49+
### Nested Schema for `bids`
50+
51+
Read-Only:
52+
53+
- `bid_name` (String)
54+
- `won_count` (Number)
55+
56+
57+
<a id="nestedatt--pending_allocations"></a>
58+
### Nested Schema for `pending_allocations`
59+
60+
Read-Only:
61+
62+
- `bid_name` (String)
63+
- `count` (Number)
64+
- `server_class` (String)
4365

4466
### Available Regions
4567

Diff for: docs/resources/spotnodepool.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ resource "spot_spotnodepool" "example" {
4141

4242
### Read-Only
4343

44-
- `id` (String) The id of the cloudspace.
44+
- `bid_status` (String) Status of the bid associated with this spotnodepool.
45+
- `id` (String) The id of the spotnodepool.
4546
- `last_updated` (String) The last time the spotnodepool was updated.
4647
- `resource_version` (String) The version of the resource known to local state. This is used to determine if the resource is modified outside of terraform.
48+
- `won_count` (Number) Number of won bids.
4749

4850
<a id="nestedatt--autoscaling"></a>
4951
### Nested Schema for `autoscaling`
@@ -91,5 +93,6 @@ Import is supported using the following syntax:
9193

9294
```shell
9395
# A spotnodepool can be imported by specifying its id.
96+
# An id of the spotnodepool is available in the cloudspace resource attributes, spotnodepool_ids, bids and pending_allocations.
9497
terraform import spot_spotnodepool.example c126b90d-00d1-48fb-92ae-b8c88e27f511
9598
```

Diff for: examples/provider/provider.tf

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ terraform {
88

99
provider "spot" {
1010
# overrides environment variables
11-
rxtspot_token = "<token>"
11+
token = "<rxtspot_token>"
1212
}

Diff for: examples/resources/spot_spotnodepool/import.sh

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# A spotnodepool can be imported by specifying its id.
2+
# An id of the spotnodepool is available in the cloudspace resource attributes, spotnodepool_ids, bids and pending_allocations.
23
terraform import spot_spotnodepool.example c126b90d-00d1-48fb-92ae-b8c88e27f511

Diff for: internal/provider/cloudspace_data_source.go

+91-6
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@ import (
44
"context"
55
"fmt"
66
"os"
7+
"strings"
8+
"time"
79

810
ngpcv1 "github.com/RSS-Engineering/ngpc-cp/api/v1"
911
"github.com/RSS-Engineering/ngpc-cp/pkg/ngpc"
1012
"github.com/hashicorp/terraform-plugin-framework/datasource"
13+
"github.com/hashicorp/terraform-plugin-framework/diag"
1114
"github.com/hashicorp/terraform-plugin-framework/types"
1215
"github.com/hashicorp/terraform-plugin-log/tflog"
1316
"github.com/rackerlabs/terraform-provider-spot/internal/provider/datasource_cloudspace"
@@ -62,13 +65,26 @@ func (d *cloudspaceDataSource) Read(ctx context.Context, req datasource.ReadRequ
6265
}
6366

6467
// Read API call logic
65-
tflog.Debug(ctx, "Computing name, namespace using resource id", map[string]any{"id": data.Id.ValueString()})
66-
name, namespace, err := getNameAndNamespaceFromId(data.Id.ValueString())
67-
if err != nil {
68-
resp.Diagnostics.AddError("Failed to get name and namespace from id", err.Error())
69-
return
68+
var err error
69+
var id, name, namespace string
70+
id = data.Id.ValueString()
71+
if strings.Contains(id, "/") {
72+
tflog.Debug(ctx, "Computing name, namespace using id", map[string]any{"id": id})
73+
name, namespace, err = getNameAndNamespaceFromId(id)
74+
if err != nil {
75+
resp.Diagnostics.AddError("Failed to get name and namespace from id", err.Error())
76+
return
77+
}
78+
} else {
79+
// In newer approach we dont include org ns in the id because users are not aware of org ns
80+
name = id
81+
namespace = os.Getenv("RXTSPOT_ORG_NS")
82+
if namespace == "" {
83+
resp.Diagnostics.AddError("Failed to get org namespace", "RXTSPOT_ORG_NS is not set")
84+
return
85+
}
86+
tflog.Debug(ctx, "Using namespace from environment", map[string]any{"namespace": namespace})
7087
}
71-
tflog.Debug(ctx, "Name, namespace using resource id", map[string]any{"name": name, "namespace": namespace})
7288
cloudspace := &ngpcv1.CloudSpace{}
7389
err = d.client.Get(ctx, ktypes.NamespacedName{
7490
Name: name,
@@ -81,11 +97,80 @@ func (d *cloudspaceDataSource) Read(ctx context.Context, req datasource.ReadRequ
8197

8298
data.Id = types.StringValue(getIDFromObjectMeta(cloudspace.ObjectMeta))
8399
data.Region = types.StringValue(cloudspace.Spec.Region)
100+
data.CloudspaceName = types.StringValue(cloudspace.ObjectMeta.Name)
84101
data.Name = types.StringValue(cloudspace.ObjectMeta.Name)
85102
data.ApiServerEndpoint = types.StringValue(cloudspace.Status.APIServerEndpoint)
86103
data.Health = types.StringValue(cloudspace.Status.Health)
87104
data.Phase = types.StringValue(string(cloudspace.Status.Phase))
88105
data.Reason = types.StringValue(cloudspace.Status.Reason)
106+
data.HacontrolPlane = types.BoolValue(cloudspace.Spec.HAControlPlane)
107+
data.FirstReadyTimestamp = types.StringValue(cloudspace.Status.FirstReadyTimestamp.Format(time.RFC3339))
108+
if cloudspace.Spec.Webhook != "" {
109+
// even if we dont set string value it becomes "" by default
110+
// assume it as Null if it is not set
111+
data.PreemptionWebhook = types.StringValue(cloudspace.Spec.Webhook)
112+
} else {
113+
data.PreemptionWebhook = types.StringNull()
114+
}
115+
var diags diag.Diagnostics
116+
data.SpotnodepoolIds, diags = types.ListValueFrom(ctx, types.StringType, cloudspace.Spec.BidRequests)
117+
resp.Diagnostics.Append(diags...)
118+
if resp.Diagnostics.HasError() {
119+
return
120+
}
121+
122+
var bidsSlice []datasource_cloudspace.BidsValue
123+
for _, val := range cloudspace.Status.Bids {
124+
var wonCount types.Int64
125+
if val.WonCount != nil {
126+
wonCount = types.Int64Value(int64(*val.WonCount))
127+
} else {
128+
wonCount = types.Int64Null()
129+
}
130+
bidObjVal, convertDiags := datasource_cloudspace.BidsValue{
131+
BidName: types.StringValue(val.BidName),
132+
WonCount: wonCount,
133+
}.ToObjectValue(ctx)
134+
resp.Diagnostics.Append(convertDiags...)
135+
if resp.Diagnostics.HasError() {
136+
return
137+
}
138+
bidObjValuable, convertDiags := datasource_cloudspace.BidsType{}.ValueFromObject(ctx, bidObjVal)
139+
resp.Diagnostics.Append(convertDiags...)
140+
if resp.Diagnostics.HasError() {
141+
return
142+
}
143+
bidsSlice = append(bidsSlice, bidObjValuable.(datasource_cloudspace.BidsValue))
144+
}
145+
data.Bids, diags = types.SetValueFrom(ctx, datasource_cloudspace.BidsValue{}.Type(ctx), bidsSlice)
146+
resp.Diagnostics.Append(diags...)
147+
if resp.Diagnostics.HasError() {
148+
return
149+
}
150+
var allocationsSlice []datasource_cloudspace.PendingAllocationsValue
151+
for _, val := range cloudspace.Status.PendingAllocations {
152+
allocObjVal, convertDiags := datasource_cloudspace.PendingAllocationsValue{
153+
BidName: types.StringValue(val.BidName),
154+
ServerClass: types.StringValue(val.ServerClassName),
155+
Count: types.Int64Value(int64(val.Count)),
156+
}.ToObjectValue(ctx)
157+
resp.Diagnostics.Append(convertDiags...)
158+
if resp.Diagnostics.HasError() {
159+
return
160+
}
161+
allocObjValuable, convertDiags := datasource_cloudspace.PendingAllocationsType{}.ValueFromObject(ctx, allocObjVal)
162+
resp.Diagnostics.Append(convertDiags...)
163+
if resp.Diagnostics.HasError() {
164+
return
165+
}
166+
allocationsSlice = append(allocationsSlice, allocObjValuable.(datasource_cloudspace.PendingAllocationsValue))
167+
}
168+
data.PendingAllocations, diags = types.SetValueFrom(ctx,
169+
datasource_cloudspace.PendingAllocationsValue{}.Type(ctx), allocationsSlice)
170+
resp.Diagnostics.Append(diags...)
171+
if resp.Diagnostics.HasError() {
172+
return
173+
}
89174

90175
token := os.Getenv("RXTSPOT_TOKEN")
91176
if token == "" {

0 commit comments

Comments
 (0)