Skip to content

Commit

Permalink
feat: introduce KVStore
Browse files Browse the repository at this point in the history
  • Loading branch information
brian-mulier-p authored Aug 5, 2024
1 parent d12c1c7 commit 36f8477
Show file tree
Hide file tree
Showing 7 changed files with 723 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .github/workflows/index.jsonl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{ "index" : { "_index" : "kestra_roles", "_id" : "admin" } }
{"id":"admin","name":"Admin", "isDefault": false,"permissions":{"FLOW":["READ","CREATE","UPDATE","DELETE"],"TEMPLATE":["READ","CREATE","UPDATE","DELETE"],"EXECUTION":["READ","CREATE","UPDATE","DELETE"],"USER":["READ","CREATE","UPDATE","DELETE"],"NAMESPACE":["READ","CREATE","UPDATE","DELETE"],"GROUP":["READ","CREATE","UPDATE","DELETE"],"ROLE":["READ","CREATE","UPDATE","DELETE"],"AUDITLOG":["READ"],"SECRET":["READ","CREATE","UPDATE","DELETE"],"BINDING":["READ","CREATE","UPDATE","DELETE"],"TENANT":["READ","CREATE","UPDATE","DELETE"]},"deleted":false}
{"id":"admin","name":"Admin", "isDefault": false,"permissions":{"FLOW":["READ","CREATE","UPDATE","DELETE"],"TEMPLATE":["READ","CREATE","UPDATE","DELETE"],"EXECUTION":["READ","CREATE","UPDATE","DELETE"],"USER":["READ","CREATE","UPDATE","DELETE"],"NAMESPACE":["READ","CREATE","UPDATE","DELETE"],"GROUP":["READ","CREATE","UPDATE","DELETE"],"ROLE":["READ","CREATE","UPDATE","DELETE"],"AUDITLOG":["READ"],"SECRET":["READ","CREATE","UPDATE","DELETE"],"BINDING":["READ","CREATE","UPDATE","DELETE"],"TENANT":["READ","CREATE","UPDATE","DELETE"],"KVSTORE":["READ","CREATE","UPDATE","DELETE"]},"deleted":false}
{ "index" : { "_index" : "kestra_roles", "_id" : "admin2" } }
{"id":"admin2","name":"Admin","tenantId":"unit_test", "isDefault": false,"permissions":{"FLOW":["READ","CREATE","UPDATE","DELETE"],"TEMPLATE":["READ","CREATE","UPDATE","DELETE"],"EXECUTION":["READ","CREATE","UPDATE","DELETE"],"USER":["READ","CREATE","UPDATE","DELETE"],"NAMESPACE":["READ","CREATE","UPDATE","DELETE"],"GROUP":["READ","CREATE","UPDATE","DELETE"],"ROLE":["READ","CREATE","UPDATE","DELETE"],"AUDITLOG":["READ"],"SECRET":["READ","CREATE","UPDATE","DELETE"],"BINDING":["READ","CREATE","UPDATE","DELETE"],"TENANT":["READ","CREATE","UPDATE","DELETE"]},"deleted":false}
{ "index" : { "_index" : "kestra_groups", "_id" : "admin" } }
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ jobs:
curl -H "Content-Type: application/x-ndjson" -XPOST "127.27.27.27:9200/_bulk?pretty" --data-binary @.github/workflows/index.jsonl
sleep 3
curl -H "Content-Type: multipart/form-data" -u [email protected]:pass -X POST -F fileContent=@internal/resources/flow.py "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/files?path=/flow.py"
curl -H "Content-Type: text/plain" -u [email protected]:pass -X PUT -d '"stringValue"' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/string"
curl -H "Content-Type: text/plain" -u [email protected]:pass -X PUT -d '1' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/int"
curl -H "Content-Type: text/plain" -u [email protected]:pass -X PUT -d '1.5' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/double"
curl -H "Content-Type: text/plain" -u [email protected]:pass -X PUT -d 'false' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/falseBoolean"
curl -H "Content-Type: text/plain" -u [email protected]:pass -X PUT -d 'true' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/trueBoolean"
curl -H "Content-Type: text/plain" -u [email protected]:pass -X PUT -d '2022-05-01T03:02:01Z' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/dateTime"
curl -H "Content-Type: text/plain" -u [email protected]:pass -X PUT -d '2022-05-01' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/date"
curl -H "Content-Type: text/plain" -u [email protected]:pass -X PUT -d 'P3DT3H2M1S' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/duration"
curl -H "Content-Type: application/json" -u [email protected]:pass -X PUT -d '{"some":"value","in":"object"}' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/object"
curl -H "Content-Type: application/json" -u [email protected]:pass -X PUT -d '[{"some":"value","in":"object"},{"yet":"another","array":"object"}]' "127.27.27.27:8080/api/v1/namespaces/io.kestra.terraform.data/kv/array"
- name: Set up Go
Expand Down
112 changes: 112 additions & 0 deletions internal/provider/data_source_kv.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package provider

import (
"context"
"encoding/json"
"fmt"
"net/http"

"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceKv() *schema.Resource {
return &schema.Resource{
Description: "Use this data source to access value for an existing Key-Value pair.",

ReadContext: dataSourceKvRead,
Schema: map[string]*schema.Schema{
"tenant_id": {
Description: "The tenant id.",
Type: schema.TypeString,
Computed: true,
},
"namespace": {
Description: "The namespace of the Key-Value pair.",
Type: schema.TypeString,
Required: true,
},
"key": {
Description: "The key to fetch value for.",
Type: schema.TypeString,
Required: true,
},
"type": {
Description: "The type of the value. One of STRING, NUMBER, BOOLEAN, DATETIME, DATE, DURATION, JSON.",
Type: schema.TypeString,
Computed: true,
},
"value": {
Description: "The fetched value.",
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceKvRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
c := meta.(*Client)
var diags diag.Diagnostics

tenantId := c.TenantId
namespace := d.Get("namespace").(string)
key := d.Get("key").(string)

url := c.Url + fmt.Sprintf("%s/namespaces/%s/kv/%s", apiRoot(tenantId), namespace, key)

req, err := http.NewRequestWithContext(ctx, "GET", fmt.Sprintf(url), nil)
if err != nil {
return diag.FromErr(err)
}

statusCode, body, reqErr := c.rawResponseRequest("GET", req)
if reqErr != nil {
if statusCode == http.StatusNotFound {
d.SetId("")
return diags
}
return diag.FromErr(reqErr.Err)
}

if tenantId != nil {
if err := d.Set("tenant_id", *tenantId); err != nil {
return diag.FromErr(err)
}
}
d.SetId(fmt.Sprintf("%s/%s", namespace, key))

var kvResponsePtr struct {
Type string `json:"type"`
Value any `json:"value"`
}
if err := json.Unmarshal(body, &kvResponsePtr); err != nil {
return diag.FromErr(err)
}
if err := d.Set("namespace", namespace); err != nil {
return diag.FromErr(err)
}
if err := d.Set("key", key); err != nil {
return diag.FromErr(err)
}
valueType := kvResponsePtr.Type
if err := d.Set("type", valueType); err != nil {
return diag.FromErr(err)
}

value := ""
if valueType == "JSON" {
valueBytes, err := json.Marshal(kvResponsePtr.Value)
if err != nil {
return diag.FromErr(err)
}
value = string(valueBytes)
} else {
value = fmt.Sprint(kvResponsePtr.Value)
}
if err := d.Set("value", value); err != nil {
return diag.FromErr(err)
}

return diags
}
161 changes: 161 additions & 0 deletions internal/provider/data_source_kv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package provider

import (
"encoding/json"
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccDataSourceKv(t *testing.T) {
resource.UnitTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProviderFactories: providerFactories,
Steps: []resource.TestStep{
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "string"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "string",
),
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "value", "stringValue",
),
),
},
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "int"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "int",
),
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "value", "1",
),
),
},
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "double"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "double",
),
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "value", "1.5",
),
),
},
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "falseBoolean"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "falseBoolean",
),
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "value", "false",
),
),
},
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "trueBoolean"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "trueBoolean",
),
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "value", "true",
),
),
},
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "dateTime"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "dateTime",
),
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "value", "2022-05-01T03:02:01Z",
),
),
},
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "date"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "date",
),
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "value", "2022-05-01",
),
),
},
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "duration"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "duration",
),
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "value", "PT75H2M1S",
),
),
},
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "object"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "object",
),
resource.TestCheckResourceAttrWith(
"data.kestra_kv.new", "value", func(value string) error {
var obj map[string]string
err := json.Unmarshal([]byte(value), &obj)
if err != nil {
return err
}
if obj["some"] == "value" && obj["in"] == "object" {
return nil
}
return fmt.Errorf("unexpected value: %s", value)
},
),
),
},
{
Config: testAccDataSourceKv("io.kestra.terraform.data", "array"),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"data.kestra_kv.new", "key", "array",
),
resource.TestCheckResourceAttrWith(
"data.kestra_kv.new", "value", func(value string) error {
var obj []map[string]string
err := json.Unmarshal([]byte(value), &obj)
if err != nil {
return err
}
if obj[0]["some"] == "value" && obj[0]["in"] == "object" &&
obj[1]["yet"] == "another" && obj[1]["array"] == "object" {
return nil
}
return fmt.Errorf("unexpected value: %s", value)
},
),
),
},
},
})
}

func testAccDataSourceKv(namespace, key any) string {
return fmt.Sprintf(
`
data "kestra_kv" "new" {
namespace = "%s"
key = "%s"
}`,
namespace,
key,
)
}
2 changes: 2 additions & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func New(version string, tenant *string) func() *schema.Provider {
"kestra_namespace_file": dataSourceNamespaceFile(),
"kestra_service_account": dataSourceServiceAccount(),
"kestra_user_api_tokens": dataSourceUserApiTokens(),
"kestra_kv": dataSourceKv(),
},
ResourcesMap: map[string]*schema.Resource{
"kestra_binding": resourceBinding(),
Expand All @@ -107,6 +108,7 @@ func New(version string, tenant *string) func() *schema.Provider {
"kestra_namespace_file": resourceNamespaceFile(),
"kestra_service_account": resourceServiceAccount(),
"kestra_user_api_token": resourceUserApiToken(),
"kestra_kv": resourceKv(),
},
}

Expand Down
Loading

0 comments on commit 36f8477

Please sign in to comment.