Skip to content

Commit

Permalink
feat(Deployments): support ParameterOpenAPISchema (#263)
Browse files Browse the repository at this point in the history
* feat(Deployments): support ParameterOpenAPISchema

Adds support for the ParameterOpenAPISchema for the Deployment resource.

Related to #238

Related to https://linear.app/prefect/issue/PLA-185/support-for-deployments-resource

* Generate Terraform Docs

* Require replacement on value change

* Update(): Remove unused parameterOpenAPISchema var

We don't update parameterOpenAPISchema because it's not supported by the
API, so we don't need to unmarshal the variable here.

* Update example with all parameters set

* Generate Terraform Docs

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
mitchnielsen and github-actions[bot] authored Oct 1, 2024
1 parent 60fb1f6 commit 5933437
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 8 deletions.
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
}
}

0 comments on commit 5933437

Please sign in to comment.