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

feat(Deployments): support ParameterOpenAPISchema #263

Merged
merged 8 commits into from
Oct 1, 2024
8 changes: 8 additions & 0 deletions docs/resources/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ resource "prefect_deployment" "deployment" {
"some-parameter" : "some-value",
"some-parameter2" : "some-value2"
})
parameter_openapi_schema = jsonencode({
"type" : "object",
"properties" : {
"some-parameter" : { "type" : "string" }
"some-parameter2" : { "type" : "string" }
}
})
path = "./foo/bar"
paused = false
storage_document_id = prefect_block.test_gh_repository.id
Expand All @@ -77,6 +84,7 @@ resource "prefect_deployment" "deployment" {
- `entrypoint` (String) The path to the entrypoint for the workflow, relative to the path.
- `job_variables` (String) Overrides for the flow's infrastructure configuration.
- `manifest_path` (String) The path to the flow's manifest file, relative to the chosen storage.
- `parameter_openapi_schema` (String) The parameter schema of the flow, including defaults.
- `parameters` (String) Parameters for flow runs scheduled by the deployment.
- `path` (String) The path to the working directory for the workflow, relative to remote storage or an absolute path.
- `paused` (Boolean) Whether or not the deployment is paused.
Expand Down
7 changes: 7 additions & 0 deletions examples/resources/prefect_deployment/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ resource "prefect_deployment" "deployment" {
"some-parameter" : "some-value",
"some-parameter2" : "some-value2"
})
parameter_openapi_schema = jsonencode({
"type" : "object",
"properties" : {
"some-parameter" : { "type" : "string" }
"some-parameter2" : { "type" : "string" }
}
})
path = "./foo/bar"
paused = false
storage_document_id = prefect_block.test_gh_repository.id
Expand Down
2 changes: 2 additions & 0 deletions internal/api/deployments.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Deployment struct {
JobVariables map[string]interface{} `json:"job_variables,omitempty"`
ManifestPath string `json:"manifest_path,omitempty"`
Name string `json:"name"`
ParameterOpenAPISchema map[string]interface{} `json:"parameter_openapi_schema,omitempty"`
Parameters map[string]interface{} `json:"parameters,omitempty"`
Path string `json:"path"`
Paused bool `json:"paused"`
Expand All @@ -47,6 +48,7 @@ type DeploymentCreate struct {
JobVariables map[string]interface{} `json:"job_variables,omitempty"`
ManifestPath string `json:"manifest_path,omitempty"`
Name string `json:"name"`
ParameterOpenAPISchema map[string]interface{} `json:"parameter_openapi_schema,omitempty"`
Parameters map[string]interface{} `json:"parameters,omitempty"`
Path string `json:"path,omitempty"`
Paused bool `json:"paused,omitempty"`
Expand Down
34 changes: 34 additions & 0 deletions internal/provider/resources/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type DeploymentResourceModel struct {
JobVariables jsontypes.Normalized `tfsdk:"job_variables"`
ManifestPath types.String `tfsdk:"manifest_path"`
Name types.String `tfsdk:"name"`
ParameterOpenAPISchema jsontypes.Normalized `tfsdk:"parameter_openapi_schema"`
Parameters jsontypes.Normalized `tfsdk:"parameters"`
Path types.String `tfsdk:"path"`
Paused types.Bool `tfsdk:"paused"`
Expand Down Expand Up @@ -238,6 +239,18 @@ func (r *DeploymentResource) Schema(_ context.Context, _ resource.SchemaRequest,
Computed: true,
CustomType: jsontypes.NormalizedType{},
},
"parameter_openapi_schema": schema.StringAttribute{
Description: "The parameter schema of the flow, including defaults.",
Optional: true,
Computed: true,
CustomType: jsontypes.NormalizedType{},
// OpenAPI schema is also only set on create, and
// we do not support modifying this value. Therefore, any changes
// to this attribute will force a replacement.
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
},
}
}
Expand Down Expand Up @@ -306,6 +319,12 @@ func (r *DeploymentResource) Create(ctx context.Context, req resource.CreateRequ
return
}

var parameterOpenAPISchema map[string]interface{}
resp.Diagnostics.Append(plan.ParameterOpenAPISchema.Unmarshal(&parameterOpenAPISchema)...)
if resp.Diagnostics.HasError() {
return
}

deployment, err := client.Create(ctx, api.DeploymentCreate{
Description: plan.Description.ValueString(),
EnforceParameterSchema: plan.EnforceParameterSchema.ValueBool(),
Expand All @@ -322,6 +341,7 @@ func (r *DeploymentResource) Create(ctx context.Context, req resource.CreateRequ
Version: plan.Version.ValueString(),
WorkPoolName: plan.WorkPoolName.ValueString(),
WorkQueueName: plan.WorkQueueName.ValueString(),
ParameterOpenAPISchema: parameterOpenAPISchema,
})
if err != nil {
resp.Diagnostics.AddError(
Expand Down Expand Up @@ -406,6 +426,12 @@ func (r *DeploymentResource) Read(ctx context.Context, req resource.ReadRequest,
}
model.JobVariables = jsontypes.NewNormalizedValue(string(jobVariablesByteSlice))

parameterOpenAPISchemaByteSlice, err := json.Marshal(deployment.ParameterOpenAPISchema)
if err != nil {
resp.Diagnostics.Append(helpers.SerializeDataErrorDiagnostic("parameter_openapi_schema", "Deployment parameter OpenAPI schema", err))
}
model.ParameterOpenAPISchema = jsontypes.NewNormalizedValue(string(parameterOpenAPISchemaByteSlice))

resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
Expand Down Expand Up @@ -515,6 +541,14 @@ func (r *DeploymentResource) Update(ctx context.Context, req resource.UpdateRequ
}
model.JobVariables = jsontypes.NewNormalizedValue(string(jobVariablesByteSlice))

parameterOpenAPISchemaByteSlice, err := json.Marshal(deployment.ParameterOpenAPISchema)
if err != nil {
resp.Diagnostics.Append(helpers.SerializeDataErrorDiagnostic("parameter_openapi_schema", "Deployment parameter OpenAPI schema", err))

return
}
model.ParameterOpenAPISchema = jsontypes.NewNormalizedValue(string(parameterOpenAPISchemaByteSlice))

resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
Expand Down
37 changes: 29 additions & 8 deletions internal/provider/resources/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package resources_test

import (
"context"
"encoding/json"
"fmt"
"strconv"
"strings"
"testing"

"github.com/google/uuid"
Expand Down Expand Up @@ -32,6 +34,7 @@ type deploymentConfig struct {
Version string
WorkPoolName string
WorkQueueName string
ParameterOpenAPISchema string

FlowName string

Expand Down Expand Up @@ -82,6 +85,7 @@ resource "prefect_deployment" "{{.DeploymentName}}" {
version = "{{.Version}}"
work_pool_name = "{{.WorkPoolName}}"
work_queue_name = "{{.WorkQueueName}}"
parameter_openapi_schema = jsonencode({{.ParameterOpenAPISchema}})
storage_document_id = prefect_block.test_gh_repository.id

workspace_id = data.prefect_workspace.evergreen.id
Expand All @@ -97,6 +101,10 @@ func TestAccResource_deployment(t *testing.T) {
deploymentName := testutils.NewRandomPrefixedString()
flowName := testutils.NewRandomPrefixedString()

parameterOpenAPISchema := `{"type": "object", "properties": {"some-parameter": {"type": "string"}}}`
var parameterOpenAPISchemaMap map[string]interface{}
_ = json.Unmarshal([]byte(parameterOpenAPISchema), &parameterOpenAPISchemaMap)

cfgCreate := deploymentConfig{
DeploymentName: deploymentName,
FlowName: flowName,
Expand All @@ -115,6 +123,7 @@ func TestAccResource_deployment(t *testing.T) {
Version: "v1.1.1",
WorkPoolName: "evergreen-pool",
WorkQueueName: "evergreen-queue",
ParameterOpenAPISchema: parameterOpenAPISchema,
StorageDocumentName: testutils.NewRandomPrefixedString(),
}

Expand Down Expand Up @@ -157,6 +166,9 @@ func TestAccResource_deployment(t *testing.T) {
// Tags: []string{"test1", "test3"}
Tags: cfgCreate.Tags,

// ParameterOpenAPISchema is not settable via the Update method.
ParameterOpenAPISchema: cfgCreate.ParameterOpenAPISchema,

StorageDocumentName: cfgCreate.StorageDocumentName,
}

Expand All @@ -170,8 +182,12 @@ func TestAccResource_deployment(t *testing.T) {
// Check creation + existence of the deployment resource
Config: fixtureAccDeployment(cfgCreate),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr(cfgCreate.DeploymentResourceName, "name", cfgCreate.DeploymentName),
resource.TestCheckResourceAttr(cfgCreate.DeploymentResourceName, "description", cfgCreate.Description),
testAccCheckDeploymentExists(cfgCreate.DeploymentResourceName, cfgCreate.WorkspaceResourceName, &deployment),
testAccCheckDeploymentValues(&deployment, expectedDeploymentValues{
name: cfgCreate.DeploymentName,
description: cfgCreate.Description,
parameterOpenapiSchema: parameterOpenAPISchemaMap,
}),
resource.TestCheckResourceAttr(cfgCreate.DeploymentResourceName, "enforce_parameter_schema", strconv.FormatBool(cfgCreate.EnforceParameterSchema)),
resource.TestCheckResourceAttr(cfgCreate.DeploymentResourceName, "entrypoint", cfgCreate.Entrypoint),
resource.TestCheckResourceAttr(cfgCreate.DeploymentResourceName, "job_variables", cfgCreate.JobVariables),
Expand All @@ -194,11 +210,10 @@ func TestAccResource_deployment(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckDeploymentExists(cfgUpdate.DeploymentResourceName, cfgUpdate.WorkspaceResourceName, &deployment),
testAccCheckDeploymentValues(&deployment, expectedDeploymentValues{
name: cfgUpdate.DeploymentName,
description: cfgUpdate.Description,
name: cfgUpdate.DeploymentName,
description: cfgUpdate.Description,
parameterOpenapiSchema: parameterOpenAPISchemaMap,
}),
resource.TestCheckResourceAttr(cfgUpdate.DeploymentResourceName, "name", cfgUpdate.DeploymentName),
resource.TestCheckResourceAttr(cfgUpdate.DeploymentResourceName, "description", cfgUpdate.Description),
resource.TestCheckResourceAttr(cfgUpdate.DeploymentResourceName, "enforce_parameter_schema", strconv.FormatBool(cfgUpdate.EnforceParameterSchema)),
resource.TestCheckResourceAttr(cfgUpdate.DeploymentResourceName, "entrypoint", cfgUpdate.Entrypoint),
resource.TestCheckResourceAttr(cfgCreate.DeploymentResourceName, "job_variables", cfgUpdate.JobVariables),
Expand Down Expand Up @@ -263,8 +278,9 @@ func testAccCheckDeploymentExists(deploymentResourceName string, workspaceResour
}

type expectedDeploymentValues struct {
name string
description string
name string
description string
parameterOpenapiSchema map[string]interface{}
}

// testAccCheckDeploymentValues is a Custom Check Function that
Expand All @@ -278,6 +294,11 @@ func testAccCheckDeploymentValues(fetchedDeployment *api.Deployment, expectedVal
return fmt.Errorf("Expected deployment description to be %s, got %s", expectedValues.description, fetchedDeployment.Description)
}

equal, diffs := helpers.ObjectsEqual(expectedValues.parameterOpenapiSchema, fetchedDeployment.ParameterOpenAPISchema)
if !equal {
return fmt.Errorf("Found unexpected differences in deployment parameter_openapi_schema: %s", strings.Join(diffs, "\n"))
}

return nil
}
}