Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[runtime] Support for storageSize, storageType, zone, and subZone #78

Merged
merged 6 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ jobs:
- uses: actions/checkout@v4
with:
path: 'terraform-provider-kaleido'

- uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.8.5"
terraform_wrapper: false

- name: Set up Go
uses: actions/setup-go@v5
Expand Down
50 changes: 49 additions & 1 deletion kaleido/platform/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ type RuntimeResourceModel struct {
Size types.String `tfsdk:"size"`
EnvironmentMemberID types.String `tfsdk:"environment_member_id"`
Stopped types.Bool `tfsdk:"stopped"`
Zone types.String `tfsdk:"zone"`
SubZone types.String `tfsdk:"sub_zone"`
StorageSize types.Int64 `tfsdk:"storage_size"`
StorageType types.String `tfsdk:"storage_type"`
}

type RuntimeAPIModel struct {
Expand All @@ -52,7 +56,11 @@ type RuntimeAPIModel struct {
EnvironmentMemberID string `json:"environmentMemberId,omitempty"`
Status string `json:"status,omitempty"`
Deleted bool `json:"deleted,omitempty"`
Stopped bool `json:"stopped,omitempty"`
Stopped bool `json:"stopped"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our API should always returns this, so if its false we still want it in serialized JSON responses. Otherwise it was being omitted and the unit tests were broken.

Zone string `json:"zone,omitempty"`
SubZone string `json:"subZone,omitempty"`
StorageSize int64 `json:"storageSize,omitempty"`
StorageType string `json:"storageType,omitempty"`
}

func RuntimeResourceFactory() resource.Resource {
Expand Down Expand Up @@ -103,6 +111,21 @@ func (r *runtimeResource) Schema(_ context.Context, _ resource.SchemaRequest, re
Optional: true,
Computed: true,
},
"zone": &schema.StringAttribute{
Optional: true,
Computed: true,
},
"sub_zone": &schema.StringAttribute{
Optional: true,
},
"storage_size": &schema.Int64Attribute{
Optional: true,
// may be computed for certain storage required runtime types, but we will not track it if the user did not provide it
},
"storage_type": &schema.StringAttribute{
Optional: true,
// may be computed for certain runtime types, but we will not track it if the user did not provide it
},
},
}
}
Expand All @@ -125,6 +148,18 @@ func (data *RuntimeResourceModel) toAPI(api *RuntimeAPIModel) {
if !data.Stopped.IsNull() {
api.Stopped = data.Stopped.ValueBool()
}
if !data.Zone.IsNull() {
api.Zone = data.Zone.ValueString()
}
if !data.SubZone.IsNull() {
api.SubZone = data.SubZone.ValueString()
}
if !data.StorageSize.IsNull() {
api.StorageSize = data.StorageSize.ValueInt64()
}
if !data.StorageType.IsNull() {
api.StorageType = data.StorageType.ValueString()
}
}

func (api *RuntimeAPIModel) toData(data *RuntimeResourceModel) {
Expand All @@ -133,6 +168,19 @@ func (api *RuntimeAPIModel) toData(data *RuntimeResourceModel) {
data.LogLevel = types.StringValue(api.LogLevel)
data.Size = types.StringValue(api.Size)
data.Stopped = types.BoolValue(api.Stopped)
data.Zone = types.StringValue(api.Zone)
if api.SubZone != "" { // the API should only return a subzone if a subzone was specified
data.SubZone = types.StringValue(api.SubZone)
}
// For storage - it is optional for the user and conditional for the runtime based on its type.
// We can't mark it computed as a result, so we only track API storage state if the user provided desired
// storage state.
if api.StorageSize > 0 && !data.StorageSize.IsNull() {
data.StorageSize = types.Int64Value(api.StorageSize)
}
if api.StorageType != "" && !data.StorageType.IsNull() {
data.StorageType = types.StringValue(api.StorageType)
}
}

func (r *runtimeResource) apiPath(data *RuntimeResourceModel) string {
Expand Down
102 changes: 101 additions & 1 deletion kaleido/platform/runtime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,31 @@ resource "kaleido_platform_runtime" "runtime1" {
config_json = jsonencode({
"setting1": "value1"
})
zone = "use2"
storage_size = 10
storage_type = "default"
}
`

var runtimeStep2 = `
resource "kaleido_platform_runtime" "runtime1" {
environment = "env1"
type = "besu"
name = "runtime1"
config_json = jsonencode({
"setting1": "value1",
"setting2": "value2",
})
log_level = "trace"
size = "large"
stopped = false
zone = "use2"
storage_size = 20
storage_type = "default"
}
`

var runtimeStep3 = `
resource "kaleido_platform_runtime" "runtime1" {
environment = "env1"
type = "besu"
Expand All @@ -51,6 +72,9 @@ resource "kaleido_platform_runtime" "runtime1" {
log_level = "trace"
size = "large"
stopped = true
zone = "use2"
storage_size = 20
storage_type = "default"
}
`

Expand All @@ -65,6 +89,10 @@ func TestRuntime1(t *testing.T) {
"GET /api/v1/environments/{env}/runtimes/{runtime}",
"PUT /api/v1/environments/{env}/runtimes/{runtime}",
"GET /api/v1/environments/{env}/runtimes/{runtime}",
"GET /api/v1/environments/{env}/runtimes/{runtime}",
"GET /api/v1/environments/{env}/runtimes/{runtime}",
"PUT /api/v1/environments/{env}/runtimes/{runtime}",
"GET /api/v1/environments/{env}/runtimes/{runtime}",
"DELETE /api/v1/environments/{env}/runtimes/{runtime}",
"GET /api/v1/environments/{env}/runtimes/{runtime}",
})
Expand All @@ -86,10 +114,63 @@ func TestRuntime1(t *testing.T) {
resource.TestCheckResourceAttr(runtime1Resource, "log_level", `info`),
resource.TestCheckResourceAttr(runtime1Resource, "size", `small`),
resource.TestCheckResourceAttr(runtime1Resource, "stopped", `false`),
resource.TestCheckResourceAttr(runtime1Resource, "zone", "use2"),
resource.TestCheckResourceAttr(runtime1Resource, "storage_size", "10"),
resource.TestCheckResourceAttr(runtime1Resource, "storage_type", "default"),
),
},
{
Config: providerConfig + runtimeStep2,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet(runtime1Resource, "id"),
resource.TestCheckResourceAttr(runtime1Resource, "name", `runtime1`),
resource.TestCheckResourceAttr(runtime1Resource, "type", `besu`),
resource.TestCheckResourceAttr(runtime1Resource, "config_json", `{"setting1":"value1","setting2":"value2"}`),
resource.TestCheckResourceAttr(runtime1Resource, "log_level", `trace`),
resource.TestCheckResourceAttr(runtime1Resource, "size", `large`),
resource.TestCheckResourceAttr(runtime1Resource, "stopped", `false`),
resource.TestCheckResourceAttr(runtime1Resource, "zone", "use2"),
resource.TestCheckResourceAttr(runtime1Resource, "storage_size", "20"),
resource.TestCheckResourceAttr(runtime1Resource, "storage_type", "default"),
func(s *terraform.State) error {
// Compare the final result on the mock-server side
id := s.RootModule().Resources[runtime1Resource].Primary.Attributes["id"]
rt := mp.runtimes[fmt.Sprintf("env1/%s", id)]
// Note the pending status is allowed to remain in runtimes, as they require at least one
// service to be created to get out of pending.
testJSONEqual(t, rt, fmt.Sprintf(`
{
"id": "%[1]s",
"created": "%[2]s",
"updated": "%[3]s",
"type": "besu",
"name": "runtime1",
"config": {
"setting1": "value1",
"setting2": "value2"
},
"loglevel": "trace",
"size": "large",
"environmentMemberId": "%[4]s",
"status": "pending",
"stopped": false,
"zone": "use2",
"storageSize": 20,
"storageType": "default"
}
`,
// generated fields that vary per test run
id,
rt.Created.UTC().Format(time.RFC3339Nano),
rt.Updated.UTC().Format(time.RFC3339Nano),
rt.EnvironmentMemberID,
))
return nil
},
),
},
{
Config: providerConfig + runtimeStep3,
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet(runtime1Resource, "id"),
resource.TestCheckResourceAttr(runtime1Resource, "name", `runtime1`),
Expand All @@ -98,6 +179,9 @@ func TestRuntime1(t *testing.T) {
resource.TestCheckResourceAttr(runtime1Resource, "log_level", `trace`),
resource.TestCheckResourceAttr(runtime1Resource, "size", `large`),
resource.TestCheckResourceAttr(runtime1Resource, "stopped", `true`),
resource.TestCheckResourceAttr(runtime1Resource, "zone", "use2"),
resource.TestCheckResourceAttr(runtime1Resource, "storage_size", "20"),
resource.TestCheckResourceAttr(runtime1Resource, "storage_type", "default"),
func(s *terraform.State) error {
// Compare the final result on the mock-server side
id := s.RootModule().Resources[runtime1Resource].Primary.Attributes["id"]
Expand All @@ -119,7 +203,10 @@ func TestRuntime1(t *testing.T) {
"size": "large",
"environmentMemberId": "%[4]s",
"status": "pending",
"stopped": true
"stopped": true,
"zone": "use2",
"storageSize": 20,
"storageType": "default"
}
`,
// generated fields that vary per test run
Expand Down Expand Up @@ -161,6 +248,16 @@ func (mp *mockPlatform) postRuntime(res http.ResponseWriter, req *http.Request)
if rt.Size == "" {
rt.Size = "small"
}
if rt.Zone == "" {
rt.Zone = "default"
}
// if they provide a SubZone its just returned back
if rt.StorageType == "" {
rt.StorageType = "default"
}
if rt.StorageSize <= 0 {
rt.StorageSize = 50
}
rt.Status = "pending"
mp.runtimes[mux.Vars(req)["env"]+"/"+rt.ID] = &rt
mp.respond(res, &rt, 201)
Expand All @@ -176,6 +273,9 @@ func (mp *mockPlatform) putRuntime(res http.ResponseWriter, req *http.Request) {
now := time.Now().UTC()
newRT.Created = rt.Created
newRT.Updated = &now
if rt.StorageSize > 0 && newRT.StorageSize < rt.StorageSize {
mp.respond(res, nil, 400)
}
newRT.Status = "pending"
mp.runtimes[mux.Vars(req)["env"]+"/"+mux.Vars(req)["runtime"]] = &newRT
mp.respond(res, &newRT, 200)
Expand Down
Loading