├── examples ├── examples │ ├── dbAndCluster │ │ ├── variables.tf │ │ ├── providers.tf │ │ ├── data.tf │ │ ├── outputs.tf │ │ ├── versions.tf │ │ └── resources.tf │ ├── search │ │ ├── providers.tf │ │ ├── data.tf │ │ ├── resources.tf │ │ ├── variables.tf │ │ └── outputs.tf │ ├── team │ │ ├── providers.tf │ │ ├── data.tf │ │ ├── versions.tf │ │ ├── resources.tf │ │ ├── variables.tf │ │ └── outputs.tf │ ├── vector_index │ │ ├── providers.tf │ │ ├── data.tf │ │ ├── resources.tf │ │ ├── outputs.tf │ │ └── variables.tf │ ├── redis_database │ │ ├── providers.tf │ │ ├── data.tf │ │ ├── versions.tf │ │ ├── resources.tf │ │ ├── variables.tf │ │ └── outputs.tf │ ├── qstash_schedule │ │ ├── providers.tf │ │ ├── variables.tf │ │ └── qstash-general.tf │ └── qstash_schedule_v2 │ │ └── main.tf ├── provider │ └── provider.tf ├── resources │ ├── upstash_qstash_topic │ │ └── resource.tf │ ├── upstash_search │ │ └── resource.tf │ ├── upstash_qstash_endpoint │ │ └── resource.tf │ ├── upstash_redis_database │ │ └── resource.tf │ ├── upstash_vector_index │ │ └── resource.tf │ ├── upstash_qstash_schedule │ │ └── resource.tf │ └── upstash_team │ │ └── resource.tf └── data-sources │ ├── upstash_team_data │ └── data-source.tf │ ├── upstash_search_data │ └── data-source.tf │ ├── upstash_vector_index_data │ └── data-source.tf │ ├── upstash_redis_database_data │ └── data-source.tf │ ├── upstash_qstash_topic_date │ └── data-source.tf │ ├── upstash_qstash_endpoint_data │ └── data-source.tf │ └── upstash_qstash_schedule_data │ └── data-source.tf ├── terraformForGit.rc ├── upstash ├── utils │ ├── basicAuth.go │ └── setAndCheckErrors.go ├── qstash_v2 │ ├── topic │ │ ├── types.go │ │ ├── data_source.go │ │ ├── resource.go │ │ ├── api_calls.go │ │ └── crud.go │ └── schedule │ │ ├── types.go │ │ ├── data_source.go │ │ ├── crud.go │ │ ├── api_calls.go │ │ └── resource.go ├── qstash │ ├── endpoint │ │ ├── types.go │ │ ├── data_source.go │ │ ├── resource.go │ │ ├── api_calls.go │ │ └── crud.go │ ├── topic │ │ ├── types.go │ │ ├── data_source.go │ │ ├── resource.go │ │ ├── api_calls.go │ │ └── crud.go │ └── schedule │ │ ├── types.go │ │ ├── data_source.go │ │ ├── api_calls.go │ │ ├── crud.go │ │ └── resource.go ├── team │ ├── types.go │ ├── data_source.go │ ├── api_calls.go │ ├── resource.go │ └── crud.go ├── search │ ├── api_calls.go │ ├── types.go │ ├── crud.go │ ├── data_source.go │ └── resource.go ├── vector │ └── index │ │ ├── api_calls.go │ │ ├── types.go │ │ ├── crud.go │ │ ├── data_source.go │ │ └── resource.go ├── redis │ └── database │ │ ├── types.go │ │ ├── api_calls.go │ │ ├── data_source.go │ │ ├── crud.go │ │ └── resource.go ├── provider.go └── client │ └── client.go ├── main.go ├── docs ├── index.md ├── data-sources │ ├── qstash_topic_data.md │ ├── qstash_topic_v2_data.md │ ├── qstash_endpoint_data.md │ ├── team_data.md │ ├── qstash_schedule_v2_data.md │ ├── qstash_schedule_data.md │ ├── search_data.md │ ├── vector_index_data.md │ └── redis_database_data.md └── resources │ ├── qstash_topic_v2.md │ ├── qstash_topic.md │ ├── qstash_endpoint.md │ ├── team.md │ ├── qstash_schedule_v2.md │ ├── qstash_schedule.md │ ├── search.md │ ├── vector_index.md │ └── redis_database.md ├── envSetters.txt ├── LICENSE ├── .github └── workflows │ ├── release.yml │ └── automated-test.yml ├── .goreleaser.yml ├── integrationtesting ├── common.go ├── upstash_team_test.go ├── upstash_redis_database_test.go └── upstash_vector_index_test.go ├── go.mod ├── README.md └── .gitignore /examples/examples/dbAndCluster/variables.tf: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/provider/provider.tf: -------------------------------------------------------------------------------- 1 | provider "upstash" { 2 | email = "FILL_HERE" 3 | api_key = "FILL_HERE" 4 | } -------------------------------------------------------------------------------- /examples/examples/search/providers.tf: -------------------------------------------------------------------------------- 1 | provider "upstash" { 2 | email = var.email 3 | api_key = var.api_key 4 | } -------------------------------------------------------------------------------- /examples/examples/team/providers.tf: -------------------------------------------------------------------------------- 1 | provider "upstash" { 2 | email = var.email 3 | api_key = var.api_key 4 | } -------------------------------------------------------------------------------- /examples/examples/vector_index/providers.tf: -------------------------------------------------------------------------------- 1 | provider "upstash" { 2 | email = var.email 3 | api_key = var.api_key 4 | } -------------------------------------------------------------------------------- /examples/examples/dbAndCluster/providers.tf: -------------------------------------------------------------------------------- 1 | provider "upstash" { 2 | api_key = "FILL_HERE" 3 | email = "FILL_HERE" 4 | } -------------------------------------------------------------------------------- /examples/examples/redis_database/providers.tf: -------------------------------------------------------------------------------- 1 | provider "upstash" { 2 | email = var.email 3 | api_key = var.api_key 4 | } -------------------------------------------------------------------------------- /examples/examples/team/data.tf: -------------------------------------------------------------------------------- 1 | data "upstash_team_data" "teamData" { 2 | team_id = resource.upstash_team.exampleTeam.team_id 3 | } 4 | 5 | -------------------------------------------------------------------------------- /examples/examples/search/data.tf: -------------------------------------------------------------------------------- 1 | data "upstash_search_data" "exampleSearchData" { 2 | id = resource.upstash_search.exampleSearchResource.id 3 | } 4 | -------------------------------------------------------------------------------- /examples/resources/upstash_qstash_topic/resource.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_qstash_topic" "exampleQstashTopic" { 2 | name = "exampleQstashTopicName" 3 | } -------------------------------------------------------------------------------- /examples/examples/vector_index/data.tf: -------------------------------------------------------------------------------- 1 | data "upstash_vector_index_data" "exampleIndexData" { 2 | id = upstash_vector_index.exampleVectorResource.id 3 | } -------------------------------------------------------------------------------- /examples/data-sources/upstash_team_data/data-source.tf: -------------------------------------------------------------------------------- 1 | data "upstash_team_data" "teamData" { 2 | team_id = resource.upstash_team.exampleTeam.team_id 3 | } 4 | -------------------------------------------------------------------------------- /examples/examples/dbAndCluster/data.tf: -------------------------------------------------------------------------------- 1 | data "upstash_redis_database_data" "databaseData" { 2 | database_id = resource.upstash_redis_database.redis.database_id 3 | } 4 | -------------------------------------------------------------------------------- /examples/examples/dbAndCluster/outputs.tf: -------------------------------------------------------------------------------- 1 | // DB outputs 2 | 3 | output "database_name" { 4 | value = data.upstash_redis_database_data.databaseData.database_name 5 | } 6 | -------------------------------------------------------------------------------- /examples/examples/redis_database/data.tf: -------------------------------------------------------------------------------- 1 | data "upstash_redis_database_data" "exampleDBData" { 2 | database_id = resource.upstash_redis_database.exampleDB.database_id 3 | } -------------------------------------------------------------------------------- /examples/data-sources/upstash_search_data/data-source.tf: -------------------------------------------------------------------------------- 1 | data "upstash_search_data" "exampleSearchData" { 2 | id = resource.upstash_search.exampleSearchResource.id 3 | } 4 | -------------------------------------------------------------------------------- /examples/data-sources/upstash_vector_index_data/data-source.tf: -------------------------------------------------------------------------------- 1 | data "upstash_vector_index_data" "vectorResourceData" { 2 | id = resource.upstash_vector_index.vectorResource.id 3 | } 4 | -------------------------------------------------------------------------------- /examples/examples/qstash_schedule/providers.tf: -------------------------------------------------------------------------------- 1 | # If you set env variable, you do not need to set these. 2 | #provider "upstash" { 3 | # email = var.email 4 | # api_key = var.api_key 5 | #} -------------------------------------------------------------------------------- /examples/data-sources/upstash_redis_database_data/data-source.tf: -------------------------------------------------------------------------------- 1 | data "upstash_redis_database_data" "exampleDBData" { 2 | database_id = resource.upstash_redis_database.exampleDB.database_id 3 | } -------------------------------------------------------------------------------- /examples/examples/team/versions.tf: -------------------------------------------------------------------------------- 1 | # terraform { 2 | # required_providers { 3 | # upstash = { 4 | # source = "upstash/upstash" 5 | # version = "X.X.X" 6 | # } 7 | # } 8 | # } -------------------------------------------------------------------------------- /terraformForGit.rc: -------------------------------------------------------------------------------- 1 | provider_installation { 2 | 3 | dev_overrides { 4 | "upstash" = "/home/runner/work/terraform-provider-upstash/terraform-provider-upstash" 5 | } 6 | direct {} 7 | } 8 | -------------------------------------------------------------------------------- /examples/data-sources/upstash_qstash_topic_date/data-source.tf: -------------------------------------------------------------------------------- 1 | data "upstash_qstash_topic_data" "exampleQstashTopicData" { 2 | topic_id = resource.upstash_qstash_topic.exampleQstashTopic.topic_id 3 | } -------------------------------------------------------------------------------- /examples/examples/dbAndCluster/versions.tf: -------------------------------------------------------------------------------- 1 | # terraform { 2 | # required_providers { 3 | # upstash = { 4 | # source = "upstash/upstash" 5 | # version = "X.X.X" 6 | # } 7 | # } 8 | # } -------------------------------------------------------------------------------- /examples/examples/redis_database/versions.tf: -------------------------------------------------------------------------------- 1 | # terraform { 2 | # required_providers { 3 | # upstash = { 4 | # source = "upstash/upstash" 5 | # version = "X.X.X" 6 | # } 7 | # } 8 | # } -------------------------------------------------------------------------------- /examples/examples/search/resources.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_search" "exampleSearchResource" { 2 | name = var.name 3 | region = var.region 4 | type = var.type 5 | } -------------------------------------------------------------------------------- /examples/resources/upstash_search/resource.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_search" "searchResource" { 2 | name = "searchResource" 3 | region = "us-central1" 4 | type = "payg" 5 | } -------------------------------------------------------------------------------- /examples/data-sources/upstash_qstash_endpoint_data/data-source.tf: -------------------------------------------------------------------------------- 1 | data "upstash_qstash_endpoint_data" "exampleQstashEndpointData" { 2 | endpoint_id = resource.upstash_qstash_endpoint.exampleQstashEndpoint.endpoint_id 3 | } -------------------------------------------------------------------------------- /examples/data-sources/upstash_qstash_schedule_data/data-source.tf: -------------------------------------------------------------------------------- 1 | data "upstash_qstash_schedule_data" "exampleQstashScheduleData" { 2 | schedule_id = resource.upstash_qstash_schedule.exampleQstashSchedule.schedule_id 3 | } -------------------------------------------------------------------------------- /examples/resources/upstash_qstash_endpoint/resource.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_qstash_endpoint" "exampleQstashEndpoint" { 2 | url = "https://***.***" 3 | topic_id = resource.upstash_qstash_topic.exampleQstashTopic.topic_id 4 | } -------------------------------------------------------------------------------- /examples/examples/team/resources.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_team" "exampleTeam" { 2 | team_name = var.team_name 3 | copy_cc = var.copy_cc 4 | team_members = var.team_members 5 | } 6 | 7 | # resource "upstash_team" "importTeam" {} 8 | -------------------------------------------------------------------------------- /examples/examples/dbAndCluster/resources.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_redis_database" "redis" { 2 | database_name = "Terraform_Upstash_Database" 3 | region = "global" 4 | primary_region = "eu-west-1" 5 | tls = true 6 | } 7 | -------------------------------------------------------------------------------- /examples/resources/upstash_redis_database/resource.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_redis_database" "exampleDB" { 2 | database_name = "Terraform DB6" 3 | region = "global" 4 | primary_region = "eu-west-1" 5 | tls = true 6 | } -------------------------------------------------------------------------------- /upstash/utils/basicAuth.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "encoding/base64" 4 | 5 | func BasicAuth(user string, password string) string { 6 | token := user + ":" + password 7 | return "Basic " + base64.StdEncoding.EncodeToString([]byte(token)) 8 | } 9 | -------------------------------------------------------------------------------- /examples/examples/qstash_schedule/variables.tf: -------------------------------------------------------------------------------- 1 | variable "email" { 2 | description = "Upstash user email" 3 | default = "" 4 | } 5 | variable "api_key" { 6 | description = "Api key for the given user" 7 | default = "" 8 | } -------------------------------------------------------------------------------- /examples/resources/upstash_vector_index/resource.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_vector_index" "vectorResource" { 2 | name = "vectorResource" 3 | similarity_function = "COSINE" 4 | dimension_count = 1536 5 | region = "us-east-1" 6 | type = "fixed" 7 | } -------------------------------------------------------------------------------- /examples/resources/upstash_qstash_schedule/resource.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_qstash_schedule" "exampleQstashSchedule" { 2 | destination = resource.upstash_qstash_topic.exampleQstashTopic.topic_id 3 | cron = "* * * * */2" 4 | 5 | # or simply provide a link 6 | # destination = "https://***.***" 7 | } 8 | -------------------------------------------------------------------------------- /examples/examples/vector_index/resources.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_vector_index" "exampleVectorResource" { 2 | name = var.name 3 | similarity_function = var.similarity_function 4 | dimension_count = var.dimension_count 5 | region = var.region 6 | type = var.type 7 | } -------------------------------------------------------------------------------- /examples/resources/upstash_team/resource.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_team" "exampleTeam" { 2 | team_name = "TerraformTeam" 3 | copy_cc = false 4 | 5 | team_members = { 6 | # Owner is the owner of the api_key. 7 | "X@Y.Z" : "owner", 8 | "A@B.C" : "dev", 9 | "E@E.F" : "finance", 10 | } 11 | } -------------------------------------------------------------------------------- /examples/examples/team/variables.tf: -------------------------------------------------------------------------------- 1 | variable "email" { 2 | description = "Upstash user email" 3 | default = "" 4 | } 5 | variable "api_key" { 6 | description = "Api key for the given user" 7 | default = "" 8 | } 9 | 10 | variable "team_name" {} 11 | variable "copy_cc" {} 12 | variable "team_members" { 13 | type = map(any) 14 | } 15 | 16 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" 6 | "github.com/upstash/terraform-provider-upstash/v2/upstash" 7 | ) 8 | 9 | func main() { 10 | plugin.Serve(&plugin.ServeOpts{ 11 | ProviderFunc: func() *schema.Provider { 12 | return upstash.Provider() 13 | }, 14 | }) 15 | } 16 | -------------------------------------------------------------------------------- /examples/examples/redis_database/resources.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_redis_database" "exampleDB" { 2 | database_name = var.database_name 3 | tls = true 4 | auto_scale = true 5 | eviction = true 6 | prod_pack = true 7 | budget = 30 8 | 9 | 10 | region = var.region 11 | primary_region = var.primary_region 12 | read_regions = var.read_regions 13 | } 14 | 15 | # resource "upstash_redis_database" "importDB" {} -------------------------------------------------------------------------------- /upstash/utils/setAndCheckErrors.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 5 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 6 | ) 7 | 8 | func SetAndCheckErrors(data *schema.ResourceData, mapping map[string]interface{}) diag.Diagnostics { 9 | for str, value := range mapping { 10 | if err := data.Set(str, value); err != nil { 11 | return diag.FromErr(err) 12 | } 13 | } 14 | return nil 15 | } 16 | -------------------------------------------------------------------------------- /upstash/qstash_v2/topic/types.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | type QStashEndpoint struct { 4 | Url string `json:"url"` 5 | } 6 | 7 | type QStashTopic struct { 8 | Name string `json:"name"` 9 | CreatedAt int64 `json:"created_at"` 10 | UpdatedAt int64 `json:"updated_at"` 11 | Endpoints []QStashEndpoint `json:"endpoints"` 12 | } 13 | 14 | type UpdateQStashTopicEndpoints struct { 15 | Endpoints []QStashEndpoint `json:"endpoints"` 16 | } 17 | -------------------------------------------------------------------------------- /upstash/qstash/endpoint/types.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | type createQstashEndpointRequest struct { 4 | Url string `json:"url"` 5 | TopicName string `json:"topicName,omitempty"` 6 | TopicId string `json:"topicId,omitempty"` 7 | } 8 | 9 | type QstashEndpoint struct { 10 | Url string `json:"url"` 11 | TopicId string `json:"topicId"` 12 | EndpointId string `json:"endpointId"` 13 | } 14 | 15 | type UpdateQstashEndpoint struct { 16 | Url string `json:"url"` 17 | } 18 | -------------------------------------------------------------------------------- /examples/examples/team/outputs.tf: -------------------------------------------------------------------------------- 1 | output "team_id" { 2 | value = data.upstash_team_data.teamData.team_id 3 | } 4 | 5 | output "team_name" { 6 | value = data.upstash_team_data.teamData.team_name 7 | } 8 | 9 | output "team_members" { 10 | value = data.upstash_team_data.teamData.team_members 11 | } 12 | 13 | output "copy_cc" { 14 | value = resource.upstash_team.exampleTeam.copy_cc 15 | } 16 | 17 | output "copy_cc_from_data" { 18 | value = data.upstash_team_data.teamData.copy_cc 19 | } 20 | -------------------------------------------------------------------------------- /upstash/qstash/topic/types.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | import "github.com/upstash/terraform-provider-upstash/v2/upstash/qstash/endpoint" 4 | 5 | type createQstashTopicRequest struct { 6 | Name string `json:"name"` 7 | } 8 | 9 | type QstashTopic struct { 10 | Name string `json:"name"` 11 | TopicId string `json:"topicId"` 12 | Endpoints []endpoint.QstashEndpoint `json:"endpoints"` 13 | } 14 | 15 | type UpdateQstashTopic struct { 16 | Name string `json:"name"` 17 | } 18 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash Provider" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash Provider 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | provider "upstash" { 17 | email = "FILL_HERE" 18 | api_key = "FILL_HERE" 19 | } 20 | ``` 21 | 22 | 23 | ## Schema 24 | 25 | ### Required 26 | 27 | - `api_key` (String, Sensitive) 28 | - `email` (String) 29 | -------------------------------------------------------------------------------- /examples/examples/search/variables.tf: -------------------------------------------------------------------------------- 1 | variable "email" { 2 | default = "" 3 | description = "Upstash user email" 4 | type = string 5 | } 6 | 7 | variable "api_key" { 8 | default = "" 9 | description = "Api key for the given user" 10 | type = string 11 | } 12 | 13 | variable "name" { 14 | default = "terraform_search" 15 | type = string 16 | } 17 | 18 | variable "region" { 19 | default = "us-central1" 20 | type = string 21 | } 22 | 23 | variable "type" { 24 | default = "payg" 25 | type = string 26 | } -------------------------------------------------------------------------------- /examples/examples/search/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = data.upstash_search_data.exampleSearchData.id 3 | } 4 | 5 | output "name" { 6 | value = data.upstash_search_data.exampleSearchData.name 7 | } 8 | 9 | output "type" { 10 | value = data.upstash_search_data.exampleSearchData.type 11 | } 12 | 13 | output "region" { 14 | value = data.upstash_search_data.exampleSearchData.region 15 | } 16 | 17 | output "creation_time" { 18 | value = data.upstash_search_data.exampleSearchData.creation_time 19 | } 20 | 21 | output "endpoint" { 22 | value = data.upstash_search_data.exampleSearchData.endpoint 23 | } 24 | -------------------------------------------------------------------------------- /examples/examples/vector_index/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = upstash_vector_index.exampleVectorResource.id 3 | } 4 | 5 | output "name" { 6 | value = upstash_vector_index.exampleVectorResource.name 7 | } 8 | 9 | output "type" { 10 | value = upstash_vector_index.exampleVectorResource.type 11 | } 12 | 13 | output "region" { 14 | value = upstash_vector_index.exampleVectorResource.region 15 | } 16 | 17 | output "dimension_count" { 18 | value = upstash_vector_index.exampleVectorResource.dimension_count 19 | } 20 | 21 | output "similarity_function" { 22 | value = upstash_vector_index.exampleVectorResource.similarity_function 23 | } 24 | -------------------------------------------------------------------------------- /docs/data-sources/qstash_topic_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_topic_data Data Source - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_topic_data (Data Source) 10 | 11 | 12 | 13 | 14 | 15 | 16 | ## Schema 17 | 18 | ### Required 19 | 20 | - `topic_id` (String) Unique Qstash Topic ID for requested topic 21 | 22 | ### Read-Only 23 | 24 | - `endpoints` (List of Map of String) Endpoints for the Qstash Topic 25 | - `id` (String) The ID of this resource. 26 | - `name` (String) Name of the Qstash Topic 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/resources/qstash_topic_v2.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_topic_v2 Resource - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_topic_v2 (Resource) 10 | 11 | 12 | 13 | 14 | 15 | 16 | ## Schema 17 | 18 | ### Required 19 | 20 | - `endpoints` (Set of String) Endpoints for the Qstash Topic 21 | - `name` (String) Name of the Qstash Topic 22 | 23 | ### Read-Only 24 | 25 | - `created_at` (Number) Creation time for Qstash Topic. 26 | - `id` (String) The ID of this resource. 27 | - `updated_at` (Number) Last Update time for Qstash Topic. 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/data-sources/qstash_topic_v2_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_topic_v2_data Data Source - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_topic_v2_data (Data Source) 10 | 11 | 12 | 13 | 14 | 15 | 16 | ## Schema 17 | 18 | ### Required 19 | 20 | - `name` (String) Name of the Qstash Topic 21 | 22 | ### Read-Only 23 | 24 | - `created_at` (Number) Creation time for Qstash Topic. 25 | - `endpoints` (Set of String) Endpoints for the Qstash Topic 26 | - `id` (String) The ID of this resource. 27 | - `updated_at` (Number) Last Update time for Qstash Topic. 28 | 29 | 30 | -------------------------------------------------------------------------------- /upstash/qstash/endpoint/data_source.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func DataSourceQstashEndpoint() *schema.Resource { 6 | return &schema.Resource{ 7 | ReadContext: resourceEndpointRead, 8 | Schema: map[string]*schema.Schema{ 9 | "topic_id": { 10 | Type: schema.TypeString, 11 | Required: true, 12 | Description: "Topic Id that the endpoint is added to", 13 | }, 14 | "endpoint_id": { 15 | Type: schema.TypeString, 16 | Computed: true, 17 | Description: "Unique Qstash Endpoint ID", 18 | }, 19 | "url": { 20 | Type: schema.TypeString, 21 | Computed: true, 22 | Description: "URL of the endpoint", 23 | }, 24 | }, 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/examples/vector_index/variables.tf: -------------------------------------------------------------------------------- 1 | variable "email" { 2 | default = "" 3 | description = "Upstash user email" 4 | type = string 5 | } 6 | 7 | variable "api_key" { 8 | default = "" 9 | description = "Api key for the given user" 10 | type = string 11 | } 12 | 13 | variable "name" { 14 | default = "terraform_index" 15 | type = string 16 | } 17 | 18 | variable "similarity_function" { 19 | default = "COSINE" 20 | type = string 21 | } 22 | 23 | variable "dimension_count" { 24 | default = 1536 25 | type = number 26 | } 27 | 28 | variable "region" { 29 | default = "us-east-1" 30 | type = string 31 | } 32 | 33 | variable "type" { 34 | default = "payg" 35 | type = string 36 | } -------------------------------------------------------------------------------- /examples/examples/redis_database/variables.tf: -------------------------------------------------------------------------------- 1 | variable "email" { 2 | description = "Upstash user email" 3 | default = "" 4 | } 5 | variable "api_key" { 6 | description = "Api key for the given user" 7 | default = "" 8 | } 9 | 10 | variable "database_name" { 11 | default = "terraform_db" 12 | } 13 | 14 | 15 | variable "multizone" { 16 | default = "true" 17 | } 18 | 19 | variable "eviction" { 20 | default = "true" 21 | } 22 | 23 | variable "auto_scale" { 24 | default = "true" 25 | } 26 | 27 | variable "region" { 28 | type = string 29 | default = "global" 30 | } 31 | 32 | variable "primary_region" { 33 | type = string 34 | default = "us-east-1" 35 | } 36 | 37 | variable "read_regions" { 38 | type = set(string) 39 | default = ["eu-central-1"] 40 | } 41 | -------------------------------------------------------------------------------- /upstash/team/types.go: -------------------------------------------------------------------------------- 1 | package team 2 | 3 | type Team struct { 4 | TeamId string `json:"team_id"` 5 | TeamName string `json:"team_name"` 6 | // not needed, if changes --> reCreate 7 | // CopyCC bool `json:"copy_cc"` 8 | 9 | // Newly added, what should be done here? 10 | TeamMembers map[string]string `json:"team_members"` 11 | } 12 | 13 | type CreateTeamRequest struct { 14 | TeamName string `json:"team_name"` 15 | CopyCC bool `json:"copy_cc"` 16 | } 17 | 18 | type GetTeamMembers struct { 19 | TeamId string `json:"team_id"` 20 | TeamName string `json:"team_name"` 21 | MemberEmail string `json:"member_email"` 22 | MemberRole string `json:"member_role"` 23 | CopyCC bool `json:"copy_cc"` 24 | } 25 | 26 | type Member struct { 27 | MemberEmail string 28 | MemberRole string 29 | } 30 | -------------------------------------------------------------------------------- /docs/resources/qstash_topic.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_topic Resource - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_topic (Resource) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "upstash_qstash_topic" "exampleQstashTopic" { 17 | name = "exampleQstashTopicName" 18 | } 19 | ``` 20 | 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `name` (String) Name of the Qstash Topic 27 | 28 | ### Read-Only 29 | 30 | - `endpoints` (List of Map of String) Endpoints for the Qstash Topic 31 | - `id` (String) The ID of this resource. 32 | - `topic_id` (String) Unique Qstash Topic ID for requested topic 33 | 34 | 35 | -------------------------------------------------------------------------------- /docs/data-sources/qstash_endpoint_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_endpoint_data Data Source - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_endpoint_data (Data Source) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | data "upstash_qstash_endpoint_data" "exampleQstashEndpointData" { 17 | endpoint_id = resource.upstash_qstash_endpoint.exampleQstashEndpoint.endpoint_id 18 | } 19 | ``` 20 | 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `topic_id` (String) Topic Id that the endpoint is added to 27 | 28 | ### Read-Only 29 | 30 | - `endpoint_id` (String) Unique Qstash Endpoint ID 31 | - `id` (String) The ID of this resource. 32 | - `url` (String) URL of the endpoint 33 | 34 | 35 | -------------------------------------------------------------------------------- /envSetters.txt: -------------------------------------------------------------------------------- 1 | export TF_CLI_CONFIG_FILE="" 2 | export UPSTASH_EMAIL="" 3 | export UPSTASH_API_KEY="" 4 | 5 | export UPSTASH_REDIS_DATABASE_NAME="TestingRedisDatabase" 6 | export UPSTASH_REDIS_DATABASE_REGION="eu-west-1" 7 | export UPSTASH_REDIS_DATABASE_TLS="true" 8 | export UPSTASH_REDIS_DATABASE_MULTIZONE="false" 9 | 10 | export UPSTASH_VECTOR_INDEX_NAME="TerraformTestingIndex" 11 | export UPSTASH_VECTOR_INDEX_REGION="us-east-1" 12 | export UPSTASH_VECTOR_INDEX_TYPE="payg" 13 | export UPSTASH_VECTOR_INDEX_DIMENSION_COUNT="1" 14 | export UPSTASH_VECTOR_INDEX_SIMILARITY_FUNCTION="COSINE" 15 | 16 | export UPSTASH_TEAM_NAME="TestingTeam" 17 | export UPSTASH_TEAM_COPY_CC="false" 18 | export UPSTASH_TEAM_OWNER="" 19 | export UPSTASH_TEAM_DEVS="dev1@a.com dev2@b.com" 20 | export UPSTASH_TEAM_FINANCES="finance1@c.com finance2@d.com" 21 | -------------------------------------------------------------------------------- /docs/data-sources/team_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_team_data Data Source - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_team_data (Data Source) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | data "upstash_team_data" "teamData" { 17 | team_id = resource.upstash_team.exampleTeam.team_id 18 | } 19 | ``` 20 | 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `team_id` (String) Unique Cluster ID for requested cluster 27 | 28 | ### Read-Only 29 | 30 | - `copy_cc` (Boolean) Whether Credit card info is copied or not 31 | - `id` (String) The ID of this resource. 32 | - `team_members` (Map of String) Members of the team. Email addresses are given as the keys with their roles as the values. 33 | - `team_name` (String) Name of the team 34 | 35 | 36 | -------------------------------------------------------------------------------- /upstash/qstash/topic/data_source.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func DataSourceQstashTopic() *schema.Resource { 8 | return &schema.Resource{ 9 | ReadContext: resourceTopicRead, 10 | Schema: map[string]*schema.Schema{ 11 | "topic_id": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | Description: "Unique Qstash Topic ID for requested topic", 15 | }, 16 | "name": { 17 | Type: schema.TypeString, 18 | Computed: true, 19 | Description: "Name of the Qstash Topic", 20 | }, 21 | "endpoints": { 22 | Type: schema.TypeList, 23 | Computed: true, 24 | Elem: &schema.Schema{ 25 | Type: schema.TypeMap, 26 | Elem: &schema.Schema{ 27 | Type: schema.TypeString, 28 | }, 29 | }, 30 | Description: "Endpoints for the Qstash Topic", 31 | }, 32 | }, 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /docs/resources/qstash_endpoint.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_endpoint Resource - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_endpoint (Resource) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "upstash_qstash_endpoint" "exampleQstashEndpoint" { 17 | url = "https://***.***" 18 | topic_id = resource.upstash_qstash_topic.exampleQstashTopic.topic_id 19 | } 20 | ``` 21 | 22 | 23 | ## Schema 24 | 25 | ### Required 26 | 27 | - `topic_id` (String) Topic Id that the endpoint is added to 28 | - `url` (String) URL of the endpoint 29 | 30 | ### Read-Only 31 | 32 | - `endpoint_id` (String) Unique Qstash Endpoint ID 33 | - `id` (String) The ID of this resource. 34 | - `topic_name` (String) Unique Qstash Topic Name for Endpoint 35 | 36 | 37 | -------------------------------------------------------------------------------- /upstash/qstash_v2/topic/data_source.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func DataSourceQstashTopic() *schema.Resource { 8 | return &schema.Resource{ 9 | ReadContext: resourceTopicRead, 10 | Schema: map[string]*schema.Schema{ 11 | "name": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | Description: "Name of the Qstash Topic", 15 | }, 16 | "created_at": { 17 | Type: schema.TypeInt, 18 | Computed: true, 19 | Description: "Creation time for Qstash Topic.", 20 | }, 21 | "updated_at": { 22 | Type: schema.TypeInt, 23 | Computed: true, 24 | Description: "Last Update time for Qstash Topic.", 25 | }, 26 | "endpoints": { 27 | Type: schema.TypeSet, 28 | Elem: &schema.Schema{ 29 | Type: schema.TypeString, 30 | }, 31 | Computed: true, 32 | Description: "Endpoints for the Qstash Topic", 33 | }, 34 | }, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/examples/qstash_schedule_v2/main.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_qstash_topic_v2" "exampleQstashTopicNew" { 2 | name = "terraform_qstash_topic" 3 | endpoints = ["https://google.com"] 4 | } 5 | 6 | resource "upstash_qstash_schedule_v2" "exampleQstashSchedule" { 7 | destination = upstash_qstash_topic_v2.exampleQstashTopicNew.name 8 | cron = "* * * * */2" 9 | delay = 3600 10 | } 11 | 12 | resource "upstash_qstash_schedule_v2" "exampleQstashSchedule2" { 13 | destination = "https://google.com" 14 | cron = "* * * * */3" 15 | forward_headers = { 16 | My-Header : "My-value" 17 | My-Header2 : "My-value2" 18 | } 19 | callback = "https://testing-url.com" 20 | body = "{\"key\": \"value\"}" 21 | method = "GET" 22 | } 23 | 24 | data "upstash_qstash_schedule_v2_data" "qstashData" { 25 | schedule_id = upstash_qstash_schedule_v2.exampleQstashSchedule2.schedule_id 26 | } 27 | 28 | output "exampleOutput" { 29 | value = data.upstash_qstash_schedule_v2_data.qstashData 30 | } 31 | -------------------------------------------------------------------------------- /upstash/team/data_source.go: -------------------------------------------------------------------------------- 1 | package team 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func DataSourceTeam() *schema.Resource { 6 | return &schema.Resource{ 7 | ReadContext: resourceRead, 8 | Schema: map[string]*schema.Schema{ 9 | "team_id": { 10 | Type: schema.TypeString, 11 | Required: true, 12 | Description: "Unique Cluster ID for requested cluster", 13 | }, 14 | "team_name": { 15 | Type: schema.TypeString, 16 | Computed: true, 17 | Description: "Name of the team", 18 | }, 19 | "copy_cc": { 20 | Type: schema.TypeBool, 21 | Computed: true, 22 | Description: "Whether Credit card info is copied or not", 23 | }, 24 | "team_members": { 25 | Type: schema.TypeMap, 26 | Computed: true, 27 | Elem: &schema.Schema{ 28 | Type: schema.TypeString, 29 | }, 30 | Description: "Members of the team. Email addresses are given as the keys with their roles as the values.", 31 | }, 32 | }, 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /docs/resources/team.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_team Resource - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_team (Resource) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "upstash_team" "exampleTeam" { 17 | team_name = "TerraformTeam" 18 | copy_cc = false 19 | 20 | team_members = { 21 | # Owner is the owner of the api_key. 22 | "X@Y.Z" : "owner", 23 | "A@B.C" : "dev", 24 | "E@E.F" : "finance", 25 | } 26 | } 27 | ``` 28 | 29 | 30 | ## Schema 31 | 32 | ### Required 33 | 34 | - `copy_cc` (Boolean) Whether Credit Card is copied 35 | - `team_members` (Map of String) Members of the team. (Owner must be specified, which is the owner of the api key.) 36 | - `team_name` (String) Name of the team 37 | 38 | ### Read-Only 39 | 40 | - `id` (String) The ID of this resource. 41 | - `team_id` (String) Unique Cluster ID for created cluster 42 | 43 | 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Upstash 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /upstash/qstash/topic/resource.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func ResourceQstashTopic() *schema.Resource { 8 | return &schema.Resource{ 9 | CreateContext: resourceTopicCreate, 10 | ReadContext: resourceTopicRead, 11 | UpdateContext: resourceTopicUpdate, 12 | DeleteContext: resourceTopicDelete, 13 | Schema: map[string]*schema.Schema{ 14 | "topic_id": { 15 | Type: schema.TypeString, 16 | Computed: true, 17 | Description: "Unique Qstash Topic ID for requested topic", 18 | }, 19 | "name": { 20 | Type: schema.TypeString, 21 | Required: true, 22 | Description: "Name of the Qstash Topic", 23 | }, 24 | "endpoints": { 25 | Type: schema.TypeList, 26 | Computed: true, 27 | Elem: &schema.Schema{ 28 | Type: schema.TypeMap, 29 | Elem: &schema.Schema{ 30 | Type: schema.TypeString, 31 | }, 32 | }, 33 | Description: "Endpoints for the Qstash Topic", 34 | }, 35 | }, 36 | Importer: &schema.ResourceImporter{ 37 | StateContext: schema.ImportStatePassthroughContext, 38 | }, 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /upstash/qstash_v2/schedule/types.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | type QstashSchedule struct { 4 | CreatedAt int64 `json:"createdAt"` 5 | ScheduleId string `json:"scheduleId"` 6 | Cron string `json:"cron"` 7 | Destination string `json:"destination"` 8 | Method string `json:"method"` 9 | Header map[string][]string `json:"header,omitempty"` 10 | Body string `json:"body,omitempty"` 11 | Retries int `json:"retries"` 12 | Delay int `json:"delay,omitempty"` 13 | Callback string `json:"callback,omitempty"` 14 | } 15 | 16 | type CreateQstashScheduleResponse struct { 17 | ScheduleId string `json:"scheduleId"` 18 | } 19 | 20 | type CreateQstashScheduleRequest struct { 21 | Destination string `json:"destination"` 22 | Body string 23 | ForwardHeaders map[string]interface{} 24 | Headers QstashScheduleHeaders 25 | } 26 | 27 | type QstashScheduleHeaders struct { 28 | ContentType string 29 | Method string 30 | Delay string 31 | Retries int 32 | Callback string 33 | Cron string 34 | } 35 | -------------------------------------------------------------------------------- /upstash/qstash/endpoint/resource.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func ResourceQstashEndpoint() *schema.Resource { 6 | return &schema.Resource{ 7 | CreateContext: resourceEndpointCreate, 8 | ReadContext: resourceEndpointRead, 9 | UpdateContext: resourceEndpointUpdate, 10 | DeleteContext: resourceEndpointDelete, 11 | Schema: map[string]*schema.Schema{ 12 | "topic_id": { 13 | Type: schema.TypeString, 14 | Required: true, 15 | ForceNew: true, 16 | Description: "Topic Id that the endpoint is added to", 17 | }, 18 | "endpoint_id": { 19 | Type: schema.TypeString, 20 | Computed: true, 21 | Description: "Unique Qstash Endpoint ID", 22 | }, 23 | "topic_name": { 24 | Type: schema.TypeString, 25 | Computed: true, 26 | Description: "Unique Qstash Topic Name for Endpoint", 27 | }, 28 | "url": { 29 | Type: schema.TypeString, 30 | Required: true, 31 | Description: "URL of the endpoint", 32 | }, 33 | }, 34 | Importer: &schema.ResourceImporter{ 35 | StateContext: schema.ImportStatePassthroughContext, 36 | }, 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /docs/data-sources/qstash_schedule_v2_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_schedule_v2_data Data Source - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_schedule_v2_data (Data Source) 10 | 11 | 12 | 13 | 14 | 15 | 16 | ## Schema 17 | 18 | ### Required 19 | 20 | - `schedule_id` (String) Unique Qstash Schedule ID for requested schedule 21 | 22 | ### Optional 23 | 24 | - `body` (String) Body to send for the POST request in string format. Needs escaping (\) double quotes. 25 | - `callback` (String) Callback URL for Qstash Schedule. 26 | - `delay` (String) Delay for Qstash Schedule. 27 | - `header` (String) Headers for the QStash schedule 28 | - `retries` (Number) Retries for Qstash Schedule requests. 29 | 30 | ### Read-Only 31 | 32 | - `created_at` (Number) Creation time for Qstash Schedule. 33 | - `cron` (String) Cron string for Qstash Schedule 34 | - `destination` (String) Destination for Qstash Schedule. Either Topic Name or valid URL 35 | - `id` (String) The ID of this resource. 36 | - `method` (String) Method of Http Request on QStash 37 | 38 | 39 | -------------------------------------------------------------------------------- /upstash/qstash/topic/api_calls.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | import ( 4 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 5 | ) 6 | 7 | func createTopic(c *client.UpstashClient, body createQstashTopicRequest) (topic QstashTopic, err error) { 8 | resp, err := c.SendPostRequest(c.GetQstashEndpoint()+"/topics", body, "Create QStash Topic", true) 9 | 10 | if err != nil { 11 | return topic, err 12 | } 13 | 14 | err = resp.ToJSON(&topic) 15 | return topic, err 16 | } 17 | 18 | func deleteTopic(c *client.UpstashClient, topicId string) (err error) { 19 | return c.SendDeleteRequest(c.GetQstashEndpoint()+"/topics/"+topicId, nil, "Delete QStash Topic", true) 20 | } 21 | 22 | func getTopic(c *client.UpstashClient, topicId string) (topic QstashTopic, err error) { 23 | 24 | resp, err := c.SendGetRequest(c.GetQstashEndpoint()+"/topics/"+topicId, "Get QStash Topic", true) 25 | 26 | if err != nil { 27 | return topic, err 28 | } 29 | 30 | err = resp.ToJSON(&topic) 31 | return topic, err 32 | } 33 | 34 | func updateTopic(c *client.UpstashClient, topicId string, body UpdateQstashTopic) (err error) { 35 | _, err = c.SendPutRequest(c.GetQstashEndpoint()+"/topics/"+topicId, body, "Update QStash Topic", true) 36 | return err 37 | } 38 | -------------------------------------------------------------------------------- /docs/data-sources/qstash_schedule_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_schedule_data Data Source - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_schedule_data (Data Source) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | data "upstash_qstash_schedule_data" "exampleQstashScheduleData" { 17 | schedule_id = resource.upstash_qstash_schedule.exampleQstashSchedule.schedule_id 18 | } 19 | ``` 20 | 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `schedule_id` (String) Unique Qstash Schedule ID for requested schedule 27 | 28 | ### Read-Only 29 | 30 | - `body` (String) Encoded body for Qstash Schedule 31 | - `created_at` (Number) Creation time for Qstash Schedule 32 | - `cron` (String) Cron string for Qstash Schedule 33 | - `destination` (String) Destination for Qstash Schedule. Either Topic ID or valid URL 34 | - `forward_headers` (Map of String) Forward headers to your API 35 | - `id` (String) The ID of this resource. 36 | - `not_before` (Number) Start time for Qstash Schedule 37 | - `retries` (Number) Retries for Qstash Schedule. Either Topic ID or valid URL 38 | 39 | 40 | -------------------------------------------------------------------------------- /upstash/qstash_v2/topic/resource.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func ResourceQstashTopic() *schema.Resource { 8 | return &schema.Resource{ 9 | CreateContext: resourceTopicCreate, 10 | ReadContext: resourceTopicRead, 11 | UpdateContext: resourceTopicUpdate, 12 | DeleteContext: resourceTopicDelete, 13 | Schema: map[string]*schema.Schema{ 14 | "name": { 15 | Type: schema.TypeString, 16 | Required: true, 17 | ForceNew: true, 18 | Description: "Name of the Qstash Topic", 19 | }, 20 | "created_at": { 21 | Type: schema.TypeInt, 22 | Computed: true, 23 | Description: "Creation time for Qstash Topic.", 24 | }, 25 | "updated_at": { 26 | Type: schema.TypeInt, 27 | Computed: true, 28 | Description: "Last Update time for Qstash Topic.", 29 | }, 30 | 31 | "endpoints": { 32 | Type: schema.TypeSet, 33 | Elem: &schema.Schema{ 34 | Type: schema.TypeString, 35 | }, 36 | Required: true, 37 | Description: "Endpoints for the Qstash Topic", 38 | }, 39 | }, 40 | Importer: &schema.ResourceImporter{ 41 | StateContext: schema.ImportStatePassthroughContext, 42 | }, 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /upstash/qstash/endpoint/api_calls.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 4 | 5 | func getEndpoint(c *client.UpstashClient, endpointId string) (endpoint QstashEndpoint, err error) { 6 | 7 | resp, err := c.SendGetRequest(c.GetQstashEndpoint()+"/endpoints/"+endpointId, "Get QStash Endpoint", true) 8 | 9 | if err != nil { 10 | return endpoint, err 11 | } 12 | 13 | err = resp.ToJSON(&endpoint) 14 | return endpoint, err 15 | } 16 | 17 | func createEndpoint(c *client.UpstashClient, body createQstashEndpointRequest) (endpoint QstashEndpoint, err error) { 18 | resp, err := c.SendPostRequest(c.GetQstashEndpoint()+"/endpoints", body, "Create QStash Endpoint", true) 19 | 20 | if err != nil { 21 | return endpoint, err 22 | } 23 | 24 | err = resp.ToJSON(&endpoint) 25 | return endpoint, err 26 | } 27 | 28 | func deleteEndpoint(c *client.UpstashClient, endpointId string) (err error) { 29 | return c.SendDeleteRequest(c.GetQstashEndpoint()+"/endpoints/"+endpointId, nil, "Delete QStash Endpoint", true) 30 | } 31 | 32 | func updateEndpoint(c *client.UpstashClient, endpointId string, body UpdateQstashEndpoint) (err error) { 33 | _, err = c.SendPutRequest(c.GetQstashEndpoint()+"/endpoints/"+endpointId, body, "Update Qstash Endpoint", true) 34 | return err 35 | } 36 | -------------------------------------------------------------------------------- /docs/resources/qstash_schedule_v2.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_schedule_v2 Resource - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_schedule_v2 (Resource) 10 | 11 | 12 | 13 | 14 | 15 | 16 | ## Schema 17 | 18 | ### Required 19 | 20 | - `cron` (String) Cron string for Qstash Schedule 21 | - `destination` (String) Destination for Qstash Schedule. Either Topic Name or valid URL 22 | 23 | ### Optional 24 | 25 | - `body` (String) Body to send for the POST request in string format. Needs escaping (\) double quotes. 26 | - `callback` (String) Callback URL for Qstash Schedule. 27 | - `content_type` (String) Content type for Qstash Scheduling. 28 | - `delay` (String) Delay for Qstash Schedule. Delay should be given in seconds 29 | - `forward_headers` (Map of String) Forward headers to your API 30 | - `method` (String) Method of Http Request on QStash 31 | - `retries` (Number) Retries for Qstash Schedule requests. 32 | 33 | ### Read-Only 34 | 35 | - `created_at` (Number) Creation time for Qstash Schedule. 36 | - `header` (String) Headers for the QStash schedule 37 | - `id` (String) The ID of this resource. 38 | - `schedule_id` (String) Unique Qstash Schedule ID for requested schedule 39 | 40 | 41 | -------------------------------------------------------------------------------- /upstash/search/api_calls.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 5 | ) 6 | 7 | func CreateSearch(c *client.UpstashClient, body CreateSearchRequest) (search Search, err error) { 8 | resp, err := c.SendPostRequest("/v2/search", body, "Create Search", false) 9 | if err != nil { 10 | return search, err 11 | } 12 | 13 | err = resp.ToJSON(&search) 14 | return search, err 15 | } 16 | 17 | func GetSearch(c *client.UpstashClient, searchId string) (search Search, err error) { 18 | resp, err := c.SendGetRequest("/v2/search/"+searchId, "Get Search", false) 19 | if err != nil { 20 | return search, err 21 | } 22 | 23 | err = resp.ToJSON(&search) 24 | return search, err 25 | } 26 | 27 | func SetSearchPlan(c *client.UpstashClient, searchId string, plan SetPlanRequest) (err error) { 28 | _, err = c.SendPostRequest("/v2/search/"+searchId+"/setplan", plan, "Set Plan for Search", false) 29 | return err 30 | } 31 | 32 | func RenameSearch(c *client.UpstashClient, searchId string, name RenameSearchRequest) (err error) { 33 | _, err = c.SendPostRequest("/v2/search/"+searchId+"/rename", name, "Rename Search", false) 34 | return err 35 | } 36 | 37 | func DeleteSearch(c *client.UpstashClient, searchId string) (err error) { 38 | return c.SendDeleteRequest("/v2/search/"+searchId, nil, "Delete Search", false) 39 | } 40 | -------------------------------------------------------------------------------- /upstash/vector/index/api_calls.go: -------------------------------------------------------------------------------- 1 | package index 2 | 3 | import ( 4 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 5 | ) 6 | 7 | func CreateIndex(c *client.UpstashClient, body CreateIndexRequest) (index Index, err error) { 8 | 9 | resp, err := c.SendPostRequest("/v2/vector/index", body, "Create Vector Index", false) 10 | 11 | if err != nil { 12 | return index, err 13 | } 14 | 15 | err = resp.ToJSON(&index) 16 | return index, err 17 | 18 | } 19 | 20 | func GetIndex(c *client.UpstashClient, indexId string) (index Index, err error) { 21 | 22 | resp, err := c.SendGetRequest("/v2/vector/index/"+indexId, "Get Vector Index", false) 23 | 24 | if err != nil { 25 | return index, err 26 | } 27 | 28 | err = resp.ToJSON(&index) 29 | return index, err 30 | 31 | } 32 | 33 | func SetIndexPlan(c *client.UpstashClient, indexId string, plan SetPlanRequest) (err error) { 34 | _, err = c.SendPostRequest("/v2/vector/index/"+indexId+"/setplan", plan, "Set Plan for Vector Index", false) 35 | 36 | return err 37 | } 38 | 39 | func RenameIndex(c *client.UpstashClient, indexId string, name RenameIndexRequest) (err error) { 40 | _, err = c.SendPostRequest("/v2/vector/index/"+indexId+"/rename", name, "Rename Vector Index", false) 41 | 42 | return err 43 | } 44 | 45 | func DeleteIndex(c *client.UpstashClient, indexId string) (err error) { 46 | return c.SendDeleteRequest("/v2/vector/index/"+indexId, nil, "Delete Vector Index", false) 47 | } 48 | -------------------------------------------------------------------------------- /upstash/qstash_v2/topic/api_calls.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | import "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 4 | 5 | func getTopic(c *client.UpstashClient, topicName string) (topic QStashTopic, err error) { 6 | 7 | resp, err := c.SendGetRequest(c.GetQstashEndpointV2()+"/topics/"+topicName, "Get QStash Topic", true) 8 | 9 | if err != nil { 10 | return topic, err 11 | } 12 | 13 | err = resp.ToJSON(&topic) 14 | return topic, err 15 | } 16 | 17 | func createTopic(c *client.UpstashClient, topicName string, body UpdateQStashTopicEndpoints) (err error) { 18 | _, err = c.SendPostRequest(c.GetQstashEndpointV2()+"/topics/"+topicName+"/endpoints", body, "Create QStash Topic", true) 19 | return err 20 | } 21 | 22 | func addEndpointsToTopic(c *client.UpstashClient, topicName string, body UpdateQStashTopicEndpoints) (err error) { 23 | _, err = c.SendPostRequest(c.GetQstashEndpointV2()+"/topics/"+topicName+"/endpoints", body, "Add QStash Endpoint for Topic", true) 24 | return err 25 | } 26 | 27 | func deleteEndpointsFromTopic(c *client.UpstashClient, topicName string, body UpdateQStashTopicEndpoints) (err error) { 28 | return c.SendDeleteRequest(c.GetQstashEndpointV2()+"/topics/"+topicName+"/endpoints", body, "Delete QStash Endpoints", true) 29 | } 30 | 31 | func deleteTopic(c *client.UpstashClient, topicName string) (err error) { 32 | return c.SendDeleteRequest(c.GetQstashEndpointV2()+"/topics/"+topicName, nil, "Delete QStash Topic", true) 33 | } 34 | -------------------------------------------------------------------------------- /upstash/qstash/schedule/types.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import "github.com/upstash/terraform-provider-upstash/v2/upstash/qstash/topic" 4 | 5 | type CreateQstashScheduleRequest struct { 6 | Destination string `json:"destination"` 7 | Body string 8 | ForwardHeaders map[string]interface{} 9 | Headers QstashScheduleHeaders 10 | } 11 | 12 | type QstashSchedule struct { 13 | Content Content `json:"content"` 14 | CreatedAt int64 `json:"createdAt"` 15 | Cron string `json:"cron"` 16 | Destination Destination `json:"destination"` 17 | ScheduleId string `json:"scheduleId"` 18 | Settings Settings `json:"settings"` 19 | } 20 | 21 | type Settings struct { 22 | Deadline int64 `json:"deadline"` 23 | NotBefore int64 `json:"notBefore"` 24 | Retries int32 `json:"retries"` 25 | } 26 | 27 | type Destination struct { 28 | Topic topic.QstashTopic `json:"topic,omitempty"` 29 | Type string `json:"type"` 30 | Url string `json:"url,omitempty"` 31 | } 32 | 33 | type Content struct { 34 | Body string `json:"body"` 35 | Header map[string]string `json:"header"` 36 | } 37 | 38 | type QstashScheduleHeaders struct { 39 | ContentType string 40 | DeduplicationId string 41 | ContentBasedDeduplication bool 42 | NotBefore int 43 | Delay string 44 | Callback string 45 | Retries int 46 | Cron string 47 | ForwardHeaders map[string]string 48 | } 49 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # This GitHub action can publish assets for release when a tag is created. 2 | # Currently its setup to run on any tag that matches the pattern "v*" (ie. v0.1.0). 3 | # 4 | # This uses an action (hashicorp/ghaction-import-gpg) that assumes you set your 5 | # private key in the `GPG_PRIVATE_KEY` secret and passphrase in the `PASSPHRASE` 6 | # secret. If you would rather own your own GPG handling, please fork this action 7 | # or use an alternative one for key handling. 8 | # 9 | # You will need to pass the `--batch` flag to `gpg` in your signing step 10 | # in `goreleaser` to indicate this is being used in a non-interactive mode. 11 | # 12 | name: release 13 | on: 14 | push: 15 | tags: 16 | - "v*" 17 | jobs: 18 | goreleaser: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v2 23 | - name: Unshallow 24 | run: git fetch --prune --unshallow 25 | - name: Set up Go 26 | uses: actions/setup-go@v2 27 | with: 28 | go-version: 1.24 29 | - name: Import GPG key 30 | id: import_gpg 31 | uses: upstash/ghaction-import-gpg@v5 32 | with: 33 | gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} 34 | - name: Run GoReleaser 35 | uses: goreleaser/goreleaser-action@v2 36 | with: 37 | version: '~> v1' 38 | args: release --clean 39 | env: 40 | GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} 41 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} 42 | -------------------------------------------------------------------------------- /examples/examples/qstash_schedule/qstash-general.tf: -------------------------------------------------------------------------------- 1 | resource "upstash_qstash_topic" "exampleQstashTopic" { 2 | name = "terraform_qstash_topic" 3 | } 4 | 5 | resource "upstash_qstash_endpoint" "ep" { 6 | url = "https://testing.com" 7 | topic_id = resource.upstash_qstash_topic.exampleQstashTopic.topic_id 8 | } 9 | 10 | resource "upstash_qstash_endpoint" "ep2" { 11 | url = "https://testing2.com" 12 | topic_id = resource.upstash_qstash_topic.exampleQstashTopic.topic_id 13 | } 14 | 15 | resource "upstash_qstash_schedule" "sch" { 16 | destination = resource.upstash_qstash_topic.exampleQstashTopic.topic_id 17 | cron = "* * * * */2" 18 | body = "{\"key\": \"value\"}" 19 | callback = "https://your-domain.x/qstash-callback" 20 | forward_headers = { 21 | My-Header : "My-value" 22 | My-Header2 : "My-value2" 23 | } 24 | } 25 | 26 | output "topic_id" { 27 | value = resource.upstash_qstash_topic.exampleQstashTopic.topic_id 28 | } 29 | 30 | output "endpoint_id" { 31 | value = resource.upstash_qstash_endpoint.ep.endpoint_id 32 | } 33 | 34 | output "schedule_id" { 35 | value = resource.upstash_qstash_schedule.sch.schedule_id 36 | } 37 | 38 | output "endpoints_of_topic" { 39 | value = resource.upstash_qstash_topic.exampleQstashTopic.endpoints 40 | } 41 | 42 | output "endpoints_of_topic2" { 43 | value = resource.upstash_qstash_schedule.sch.body 44 | } 45 | 46 | 47 | # resource "upstash_qstash_endpoint" "importEP" {} 48 | 49 | # resource "upstash_qstash_schedule" "importSCH" {} 50 | 51 | # resource "upstash_qstash_topic" "importQstashTopic" {} -------------------------------------------------------------------------------- /upstash/search/types.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | type Search struct { 4 | Id string `json:"id"` 5 | Name string `json:"name"` 6 | Endpoint string `json:"endpoint"` 7 | Token string `json:"token"` 8 | ReadOnlyToken string `json:"read_only_token"` 9 | Type string `json:"type"` 10 | Region string `json:"region"` 11 | CreationTime int64 `json:"creation_time"` 12 | MaxVectorCount int64 `json:"max_vector_count"` 13 | MaxDailyUpdates int64 `json:"max_daily_updates"` 14 | MaxDailyQueries int64 `json:"max_daily_queries"` 15 | MaxMonthlyBandwidth int64 `json:"max_monthly_bandwidth"` 16 | MaxWritesPerSecond int64 `json:"max_writes_per_second"` 17 | MaxQueryPerSecond int64 `json:"max_query_per_second"` 18 | MaxReadsPerRequest int64 `json:"max_reads_per_request"` 19 | MaxWritesPerRequest int64 `json:"max_writes_per_request"` 20 | MaxTotalMetadataSize int64 `json:"max_total_metadata_size"` 21 | ReservedPrice float64 `json:"reserved_price"` 22 | CustomerId string `json:"customer_id"` 23 | } 24 | 25 | type CreateSearchRequest struct { 26 | Name string `json:"name"` 27 | Region string `json:"region"` 28 | Type string `json:"type"` 29 | } 30 | 31 | type SetPlanRequest struct { 32 | TargetPlan string `json:"target_plan"` 33 | } 34 | 35 | type TransferSearchRequest struct { 36 | TargetAccount string `json:"target_account"` 37 | } 38 | 39 | type RenameSearchRequest struct { 40 | Name string `json:"name"` 41 | } 42 | -------------------------------------------------------------------------------- /upstash/team/api_calls.go: -------------------------------------------------------------------------------- 1 | package team 2 | 3 | import ( 4 | "github.com/imroc/req" 5 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 6 | ) 7 | 8 | func createTeam(c *client.UpstashClient, body CreateTeamRequest) (team Team, err error) { 9 | 10 | resp, err := c.SendPostRequest("/v2/team", body, "Create Team", false) 11 | 12 | if err != nil { 13 | return team, err 14 | } 15 | 16 | err = resp.ToJSON(&team) 17 | return team, err 18 | 19 | } 20 | 21 | func getTeamMembers(c *client.UpstashClient, teamId string) (teamMembers []GetTeamMembers, err error) { 22 | 23 | resp, err := c.SendGetRequest("/v2/teams/"+teamId, "Get Team Members", false) 24 | 25 | if err != nil { 26 | return teamMembers, err 27 | } 28 | 29 | err = resp.ToJSON(&teamMembers) 30 | return teamMembers, err 31 | 32 | } 33 | 34 | func deleteTeam(c *client.UpstashClient, teamId string) (err error) { 35 | 36 | return c.SendDeleteRequest("/v2/team/"+teamId, nil, "Delete Team", false) 37 | 38 | } 39 | 40 | func addMember(c *client.UpstashClient, teamId string, email string, role string) (err error) { 41 | 42 | param := req.Param{ 43 | "team_id": teamId, 44 | "member_email": email, 45 | "member_role": role, 46 | } 47 | 48 | _, err = c.SendPostRequest("/v2/teams/member", param, "Add Member to Team", false) 49 | 50 | return err 51 | 52 | } 53 | 54 | func removeMember(c *client.UpstashClient, teamId string, email string) (err error) { 55 | 56 | param := req.Param{ 57 | "team_id": teamId, 58 | "member_email": email, 59 | } 60 | 61 | return c.SendDeleteRequest("/v2/teams/member", param, "Remove Team Member", false) 62 | 63 | } 64 | -------------------------------------------------------------------------------- /upstash/qstash/schedule/data_source.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func DataSourceQstashSchedule() *schema.Resource { 8 | return &schema.Resource{ 9 | ReadContext: resourceScheduleRead, 10 | Schema: map[string]*schema.Schema{ 11 | "schedule_id": { 12 | Type: schema.TypeString, 13 | Required: true, 14 | Description: "Unique Qstash Schedule ID for requested schedule", 15 | }, 16 | "cron": { 17 | Type: schema.TypeString, 18 | Computed: true, 19 | Description: "Cron string for Qstash Schedule", 20 | }, 21 | "destination": { 22 | Type: schema.TypeString, 23 | Computed: true, 24 | Description: "Destination for Qstash Schedule. Either Topic ID or valid URL", 25 | }, 26 | "retries": { 27 | Type: schema.TypeInt, 28 | Computed: true, 29 | Description: "Retries for Qstash Schedule. Either Topic ID or valid URL", 30 | }, 31 | "not_before": { 32 | Type: schema.TypeInt, 33 | Computed: true, 34 | Description: "Start time for Qstash Schedule", 35 | }, 36 | "created_at": { 37 | Type: schema.TypeInt, 38 | Computed: true, 39 | Description: "Creation time for Qstash Schedule", 40 | }, 41 | "body": { 42 | Type: schema.TypeString, 43 | Computed: true, 44 | Description: "Encoded body for Qstash Schedule", 45 | }, 46 | "forward_headers": { 47 | Type: schema.TypeMap, 48 | Computed: true, 49 | Elem: &schema.Schema{ 50 | Type: schema.TypeString, 51 | }, 52 | Description: "Forward headers to your API", 53 | }, 54 | }, 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /docs/resources/qstash_schedule.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_qstash_schedule Resource - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_qstash_schedule (Resource) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "upstash_qstash_schedule" "exampleQstashSchedule" { 17 | destination = resource.upstash_qstash_topic.exampleQstashTopic.topic_id 18 | cron = "* * * * */2" 19 | 20 | # or simply provide a link 21 | # destination = "https://***.***" 22 | } 23 | ``` 24 | 25 | 26 | ## Schema 27 | 28 | ### Required 29 | 30 | - `cron` (String) Cron string for Qstash Schedule 31 | - `destination` (String) Destination for Qstash Schedule. Either Topic ID or valid URL 32 | 33 | ### Optional 34 | 35 | - `body` (String) Body to send for the POST request in string format. Needs escaping (\) double quotes. 36 | - `callback` (String) Callback URL for Qstash Schedule. 37 | - `content_based_deduplication` (Boolean) Content Based Deduplication (bool) for Qstash Scheduling. 38 | - `content_type` (String) Content type for Qstash Scheduling. 39 | - `deduplication_id` (String) Deduplication ID for Qstash Scheduling. 40 | - `delay` (String) Delay for Qstash Schedule. 41 | - `forward_headers` (Map of String) Forward headers to your API 42 | - `not_before` (Number) Start time for Qstash Scheduling. 43 | - `retries` (Number) Retries for Qstash Schedule requests. 44 | 45 | ### Read-Only 46 | 47 | - `created_at` (Number) Creation time for Qstash Schedule. 48 | - `id` (String) The ID of this resource. 49 | - `schedule_id` (String) Unique Qstash Schedule ID for requested schedule 50 | 51 | 52 | -------------------------------------------------------------------------------- /upstash/team/resource.go: -------------------------------------------------------------------------------- 1 | package team 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 7 | ) 8 | 9 | func ResourceTeam() *schema.Resource { 10 | return &schema.Resource{ 11 | CreateContext: resourceCreate, 12 | ReadContext: resourceRead, 13 | UpdateContext: resourceUpdate, 14 | DeleteContext: resourceDelete, 15 | Schema: map[string]*schema.Schema{ 16 | "team_id": { 17 | Type: schema.TypeString, 18 | Computed: true, 19 | Description: "Unique Cluster ID for created cluster", 20 | }, 21 | "team_name": { 22 | Type: schema.TypeString, 23 | Required: true, 24 | ForceNew: true, 25 | Description: "Name of the team", 26 | }, 27 | "copy_cc": { 28 | Type: schema.TypeBool, 29 | Required: true, 30 | ForceNew: true, 31 | Description: "Whether Credit Card is copied", 32 | }, 33 | "team_members": { 34 | Type: schema.TypeMap, 35 | Required: true, 36 | ForceNew: false, 37 | Elem: &schema.Schema{ 38 | Type: schema.TypeString, 39 | }, 40 | Description: "Members of the team. (Owner must be specified, which is the owner of the api key.)", 41 | ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) { 42 | noOwner := true 43 | for _, b := range val.(map[string]interface{}) { 44 | if b.(string) == "owner" { 45 | noOwner = false 46 | } 47 | } 48 | if noOwner { 49 | errs = append(errs, fmt.Errorf("Owner of the api key should be given the role of owner")) 50 | } 51 | return 52 | }, 53 | }, 54 | }, 55 | Importer: &schema.ResourceImporter{ 56 | StateContext: schema.ImportStatePassthroughContext, 57 | }, 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | # Visit https://goreleaser.com for documentation on how to customize this 2 | # behavior. 3 | before: 4 | hooks: 5 | # this is just an example and not a requirement for provider building/publishing 6 | - go mod tidy 7 | builds: 8 | - env: 9 | # goreleaser does not work with CGO, it could also complicate 10 | # usage by users in CI/CD systems like Terraform Cloud where 11 | # they are unable to install libraries. 12 | - CGO_ENABLED=0 13 | mod_timestamp: "{{ .CommitTimestamp }}" 14 | flags: 15 | - -trimpath 16 | ldflags: 17 | - "-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}" 18 | goos: 19 | - freebsd 20 | - windows 21 | - linux 22 | - darwin 23 | goarch: 24 | - amd64 25 | - "386" 26 | - arm 27 | - arm64 28 | ignore: 29 | - goos: darwin 30 | goarch: "386" 31 | binary: "{{ .ProjectName }}_v{{ .Version }}" 32 | archives: 33 | - format: zip 34 | name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}" 35 | checksum: 36 | name_template: "{{ .ProjectName }}_{{ .Version }}_SHA256SUMS" 37 | algorithm: sha256 38 | signs: 39 | - artifacts: checksum 40 | args: 41 | # if you are using this is a GitHub action or some other automated pipeline, you 42 | # need to pass the batch flag to indicate its not interactive. 43 | - "--batch" 44 | - "--local-user" 45 | - "{{ .Env.GPG_FINGERPRINT }}" # set this environment variable for your signing key 46 | - "--output" 47 | - "${signature}" 48 | - "--detach-sign" 49 | - "${artifact}" 50 | release: 51 | # If you want to manually examine the release before its live, uncomment this line: 52 | # draft: true 53 | changelog: 54 | skip: true -------------------------------------------------------------------------------- /upstash/vector/index/types.go: -------------------------------------------------------------------------------- 1 | package index 2 | 3 | type Index struct { 4 | Id string `json:"id"` 5 | Name string `json:"name"` 6 | SimilarityFunction string `json:"similarity_function"` 7 | DimensionCount int `json:"dimension_count"` 8 | Endpoint string `json:"endpoint"` 9 | Token string `json:"token"` 10 | ReadOnlyToken string `json:"read_only_token"` 11 | Type string `json:"type"` 12 | Region string `json:"region"` 13 | CreationTime int64 `json:"creation_time"` 14 | MaxVectorCount int64 `json:"max_vector_count"` 15 | MaxDailyUpdates int64 `json:"max_daily_updates"` 16 | MaxDailyQueries int64 `json:"max_daily_queries"` 17 | MaxMonthlyBandwidth int64 `json:"max_monthly_bandwidth"` 18 | MaxWritesPerSecond int64 `json:"max_writes_per_second"` 19 | MaxQueryPerSecond int64 `json:"max_query_per_second"` 20 | MaxReadsPerRequest int64 `json:"max_reads_per_request"` 21 | MaxWritesPerRequest int64 `json:"max_writes_per_request"` 22 | MaxTotalMetadataSize int64 `json:"max_total_metadata_size"` 23 | ReservedPrice float64 `json:"reserved_price"` 24 | CustomerId string `json:"customer_id"` 25 | } 26 | 27 | type CreateIndexRequest struct { 28 | Name string `json:"name"` 29 | SimilarityFunction string `json:"similarity_function"` 30 | DimensionCount int `json:"dimension_count"` 31 | Region string `json:"region"` 32 | Type string `json:"type"` 33 | } 34 | 35 | type SetPlanRequest struct { 36 | TargetPlan string `json:"target_plan"` 37 | } 38 | 39 | type TransferIndexRequest struct { 40 | TargetAccount string `json:"target_account"` 41 | } 42 | 43 | type RenameIndexRequest struct { 44 | Name string `json:"name"` 45 | } 46 | -------------------------------------------------------------------------------- /upstash/qstash_v2/schedule/data_source.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func DataSourceQstashSchedule() *schema.Resource { 8 | return &schema.Resource{ 9 | ReadContext: resourceScheduleRead, 10 | Schema: map[string]*schema.Schema{ 11 | "created_at": { 12 | Type: schema.TypeInt, 13 | Computed: true, 14 | Description: "Creation time for Qstash Schedule.", 15 | }, 16 | "schedule_id": { 17 | Type: schema.TypeString, 18 | Required: true, 19 | Description: "Unique Qstash Schedule ID for requested schedule", 20 | }, 21 | "cron": { 22 | Type: schema.TypeString, 23 | Computed: true, 24 | Description: "Cron string for Qstash Schedule", 25 | }, 26 | "destination": { 27 | Type: schema.TypeString, 28 | Computed: true, 29 | Description: "Destination for Qstash Schedule. Either Topic Name or valid URL", 30 | }, 31 | "method": { 32 | Type: schema.TypeString, 33 | Computed: true, 34 | Description: "Method of Http Request on QStash", 35 | }, 36 | "header": { 37 | Type: schema.TypeString, 38 | Optional: true, 39 | Description: "Headers for the QStash schedule", 40 | }, 41 | "body": { 42 | Type: schema.TypeString, 43 | Optional: true, 44 | Description: "Body to send for the POST request in string format. Needs escaping (\\) double quotes.", 45 | }, 46 | "retries": { 47 | Type: schema.TypeInt, 48 | Optional: true, 49 | Default: 3, 50 | Description: "Retries for Qstash Schedule requests.", 51 | }, 52 | "delay": { 53 | Type: schema.TypeString, 54 | Optional: true, 55 | Description: "Delay for Qstash Schedule.", 56 | }, 57 | "callback": { 58 | Type: schema.TypeString, 59 | Optional: true, 60 | Description: "Callback URL for Qstash Schedule.", 61 | }, 62 | }, 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /integrationtesting/common.go: -------------------------------------------------------------------------------- 1 | package integrationtesting 2 | 3 | import ( 4 | "os" 5 | "strconv" 6 | "strings" 7 | ) 8 | 9 | var email, apikey string 10 | 11 | type EnvVars struct { 12 | Email string 13 | Apikey string 14 | 15 | RedisDatabaseName string 16 | RedisDatabaseRegion string 17 | RedisDatabaseTls bool 18 | RedisDatabaseMultiZone bool 19 | 20 | VectorIndexName string 21 | VectorIndexType string 22 | VectorIndexRegion string 23 | VectorIndexDimensionCount int 24 | VectorIndexSimilarityFunction string 25 | 26 | TeamName string 27 | CopyCC bool 28 | TeamMembers map[string]string 29 | } 30 | 31 | func GetEnvVars() EnvVars { 32 | vectorIndexDimensionCount, _ := strconv.Atoi(os.Getenv("UPSTASH_VECTOR_INDEX_DIMENSION_COUNT")) 33 | 34 | teamMembers := make(map[string]string) 35 | 36 | teamOwner := strings.Fields(os.Getenv("UPSTASH_TEAM_OWNER")) 37 | if len(teamOwner) != 0 { 38 | teamMembers[teamOwner[0]] = "owner" 39 | } 40 | 41 | teamDevs := strings.Fields(os.Getenv("UPSTASH_TEAM_DEVS")) 42 | teamFinances := strings.Fields(os.Getenv("UPSTASH_TEAM_FINANCES")) 43 | 44 | for _, val := range teamDevs { 45 | teamMembers[val] = "dev" 46 | } 47 | 48 | for _, val := range teamFinances { 49 | teamMembers[val] = "finance" 50 | } 51 | 52 | return EnvVars{ 53 | Email: os.Getenv("UPSTASH_EMAIL"), 54 | Apikey: os.Getenv("UPSTASH_API_KEY"), 55 | 56 | RedisDatabaseName: os.Getenv("UPSTASH_REDIS_DATABASE_NAME"), 57 | RedisDatabaseRegion: os.Getenv("UPSTASH_REDIS_DATABASE_REGION"), 58 | RedisDatabaseTls: os.Getenv("UPSTASH_REDIS_DATABASE_TLS") == "true", 59 | RedisDatabaseMultiZone: os.Getenv("UPSTASH_REDIS_DATABASE_MULTIZONE") == "true", 60 | 61 | VectorIndexName: os.Getenv("UPSTASH_VECTOR_INDEX_NAME"), 62 | VectorIndexType: os.Getenv("UPSTASH_VECTOR_INDEX_TYPE"), 63 | VectorIndexRegion: os.Getenv("UPSTASH_VECTOR_INDEX_REGION"), 64 | VectorIndexDimensionCount: vectorIndexDimensionCount, 65 | VectorIndexSimilarityFunction: os.Getenv("UPSTASH_VECTOR_INDEX_SIMILARITY_FUNCTION"), 66 | 67 | TeamName: os.Getenv("UPSTASH_TEAM_NAME"), 68 | CopyCC: os.Getenv("UPSTASH_TEAM_COPY_CC") == "true", 69 | TeamMembers: teamMembers, 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /.github/workflows/automated-test.yml: -------------------------------------------------------------------------------- 1 | name: 'Automated Tests' 2 | 3 | on: 4 | # Every day, at 22.00 5 | schedule: 6 | - cron: "40 11 * * *" 7 | pull_request: 8 | 9 | 10 | jobs: 11 | tests: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: PWD 16 | run: pwd 17 | - name: Set up Go 18 | uses: actions/setup-go@v2 19 | with: 20 | go-version: 1.24 21 | - name: Build provider 22 | run: go build . 23 | - name: Test 24 | id: "testing" 25 | working-directory: integrationtesting 26 | env: 27 | UPSTASH_EMAIL: ${{ secrets.UPSTASH_EMAIL }} 28 | UPSTASH_API_KEY: ${{ secrets.UPSTASH_API_KEY }} 29 | TF_CLI_CONFIG_FILE: ${{ secrets.TF_CLI_CONFIG_FILE }} 30 | UPSTASH_REDIS_DATABASE_NAME: ${{ secrets.UPSTASH_REDIS_DATABASE_NAME }} 31 | UPSTASH_REDIS_DATABASE_REGION: ${{ secrets.UPSTASH_REDIS_DATABASE_REGION }} 32 | UPSTASH_REDIS_DATABASE_TLS: ${{ secrets.UPSTASH_REDIS_DATABASE_TLS }} 33 | UPSTASH_REDIS_DATABASE_MULTIZONE: ${{ secrets.UPSTASH_REDIS_DATABASE_MULTIZONE }} 34 | UPSTASH_TEAM_NAME: ${{ secrets.UPSTASH_TEAM_NAME }} 35 | UPSTASH_TEAM_COPY_CC: ${{ secrets.UPSTASH_TEAM_COPY_CC }} 36 | UPSTASH_TEAM_OWNER: ${{ secrets.UPSTASH_TEAM_OWNER }} 37 | UPSTASH_TEAM_DEVS: ${{ secrets.UPSTASH_TEAM_DEVS }} 38 | UPSTASH_TEAM_FINANCES: ${{ secrets.UPSTASH_TEAM_FINANCES }} 39 | UPSTASH_VECTOR_INDEX_NAME: ${{ secrets.UPSTASH_VECTOR_INDEX_NAME }} 40 | UPSTASH_VECTOR_INDEX_REGION: ${{ secrets.UPSTASH_VECTOR_INDEX_REGION }} 41 | UPSTASH_VECTOR_INDEX_TYPE: ${{ secrets.UPSTASH_VECTOR_INDEX_TYPE }} 42 | UPSTASH_VECTOR_INDEX_DIMENSION_COUNT: ${{ secrets.UPSTASH_VECTOR_INDEX_DIMENSION_COUNT }} 43 | UPSTASH_VECTOR_INDEX_SIMILARITY_FUNCTION: ${{ secrets.UPSTASH_VECTOR_INDEX_SIMILARITY_FUNCTION }} 44 | run: go test -v * 45 | - name: Check on failures 46 | env: 47 | SLACK_WEBHOOK: ${{secrets.SLACK_WEBHOOK}} 48 | if: always() && steps.testing.outcome != 'success' 49 | run: | 50 | curl -X POST -H 'Content-type: application/json' --data '{"text":"Some tests have failed. Check the repo: '$GITHUB_SERVER_URL'/'$GITHUB_REPOSITORY'/actions/runs/'$GITHUB_RUN_ID'"}' "$SLACK_WEBHOOK" 51 | shell: bash 52 | -------------------------------------------------------------------------------- /upstash/qstash/endpoint/crud.go: -------------------------------------------------------------------------------- 1 | package endpoint 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 9 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 10 | ) 11 | 12 | func resourceEndpointRead(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 13 | c := m.(*client.UpstashClient) 14 | endpointId := data.Get("endpoint_id").(string) 15 | if endpointId == "" { 16 | endpointId = data.Id() 17 | } 18 | 19 | endpoint, err := getEndpoint(c, endpointId) 20 | if err != nil { 21 | return diag.FromErr(err) 22 | } 23 | 24 | data.SetId("upstash-qstash-endpoint-" + endpoint.EndpointId) 25 | 26 | mapping := map[string]interface{}{ 27 | "endpoint_id": endpoint.EndpointId, 28 | "topic_id": endpoint.TopicId, 29 | "url": endpoint.Url, 30 | } 31 | 32 | return utils.SetAndCheckErrors(data, mapping) 33 | } 34 | 35 | func resourceEndpointCreate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 36 | c := m.(*client.UpstashClient) 37 | endpoint, err := createEndpoint(c, createQstashEndpointRequest{ 38 | TopicName: data.Get("topic_name").(string), 39 | TopicId: data.Get("topic_id").(string), 40 | Url: data.Get("url").(string), 41 | }) 42 | if err != nil { 43 | return diag.FromErr(err) 44 | } 45 | data.SetId("upstash-qstash-endpoint-" + endpoint.EndpointId) 46 | data.Set("endpoint_id", endpoint.EndpointId) 47 | return resourceEndpointRead(ctx, data, m) 48 | } 49 | 50 | func resourceEndpointDelete(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 51 | c := m.(*client.UpstashClient) 52 | endpointId := data.Get("endpoint_id").(string) 53 | err := deleteEndpoint(c, endpointId) 54 | if err != nil { 55 | return diag.FromErr(err) 56 | } 57 | return nil 58 | } 59 | 60 | func resourceEndpointUpdate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 61 | c := m.(*client.UpstashClient) 62 | endpointId := data.Get("endpoint_id").(string) 63 | if data.HasChange("url") { 64 | err := updateEndpoint(c, endpointId, UpdateQstashEndpoint{ 65 | Url: data.Get("url").(string), 66 | }) 67 | 68 | if err != nil { 69 | return diag.FromErr(err) 70 | } 71 | } 72 | return resourceEndpointRead(ctx, data, m) 73 | } 74 | -------------------------------------------------------------------------------- /upstash/qstash/topic/crud.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 9 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 10 | ) 11 | 12 | func resourceTopicRead(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 13 | c := m.(*client.UpstashClient) 14 | topicId := data.Get("topic_id").(string) 15 | if topicId == "" { 16 | topicId = data.Id() 17 | } 18 | 19 | topic, err := getTopic(c, topicId) 20 | 21 | if err != nil { 22 | return diag.FromErr(err) 23 | } 24 | 25 | data.SetId("upstash-qstash-topic-" + topic.TopicId) 26 | 27 | endpointMap := []map[string]string{} 28 | for _, val := range topic.Endpoints { 29 | endpointMap = append(endpointMap, map[string]string{ 30 | "url": val.Url, 31 | "endpoint_id": val.EndpointId, 32 | "topic_id": val.TopicId, 33 | }) 34 | } 35 | 36 | mapping := map[string]interface{}{ 37 | "name": topic.Name, 38 | "topic_id": topic.TopicId, 39 | "endpoints": endpointMap, 40 | } 41 | 42 | return utils.SetAndCheckErrors(data, mapping) 43 | } 44 | 45 | func resourceTopicCreate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 46 | c := m.(*client.UpstashClient) 47 | topic, err := createTopic(c, createQstashTopicRequest{ 48 | Name: data.Get("name").(string), 49 | }) 50 | if err != nil { 51 | return diag.FromErr(err) 52 | } 53 | data.SetId("upstash-qstash-topic-" + topic.TopicId) 54 | data.Set("topic_id", topic.TopicId) 55 | return resourceTopicRead(ctx, data, m) 56 | } 57 | 58 | func resourceTopicDelete(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 59 | c := m.(*client.UpstashClient) 60 | topicId := data.Get("topic_id").(string) 61 | err := deleteTopic(c, topicId) 62 | if err != nil { 63 | return diag.FromErr(err) 64 | } 65 | return nil 66 | } 67 | 68 | func resourceTopicUpdate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 69 | c := m.(*client.UpstashClient) 70 | topicId := data.Get("topic_id").(string) 71 | if data.HasChange("name") { 72 | err := updateTopic(c, topicId, UpdateQstashTopic{ 73 | Name: data.Get("name").(string), 74 | }) 75 | 76 | if err != nil { 77 | return diag.FromErr(err) 78 | } 79 | } 80 | return resourceTopicRead(ctx, data, m) 81 | } 82 | -------------------------------------------------------------------------------- /integrationtesting/upstash_team_test.go: -------------------------------------------------------------------------------- 1 | package integrationtesting 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/gruntwork-io/terratest/modules/terraform" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var team_name string 11 | var team_copy_cc bool 12 | var team_members map[string]string 13 | 14 | func TestUpstashTeamMAIN(t *testing.T) { 15 | t.Parallel() 16 | 17 | envVars := GetEnvVars() 18 | 19 | email = envVars.Email 20 | apikey = envVars.Apikey 21 | 22 | team_name = envVars.TeamName 23 | team_copy_cc = envVars.CopyCC 24 | team_members = envVars.TeamMembers 25 | 26 | terraformOptions := teamOptions(t) 27 | 28 | defer terraform.Destroy(t, terraformOptions) 29 | 30 | terraform.Apply(t, terraformOptions) 31 | terraform.Plan(t, terraformOptions) 32 | teamAsserter(t, terraformOptions) 33 | } 34 | 35 | func UpstashTeamRecreate(t *testing.T) { 36 | 37 | team_name = team_name + "Updated" 38 | team_copy_cc = !team_copy_cc 39 | 40 | terraformOptions := teamOptions(t) 41 | terraform.Apply(t, terraformOptions) 42 | terraform.Plan(t, terraformOptions) 43 | teamAsserter(t, terraformOptions) 44 | 45 | } 46 | 47 | func teamOptions(t *testing.T) *terraform.Options { 48 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 49 | TerraformDir: "../examples/examples/team", 50 | Vars: map[string]interface{}{ 51 | "email": email, 52 | "api_key": apikey, 53 | 54 | "team_name": team_name, 55 | "copy_cc": team_copy_cc, 56 | "team_members": team_members, 57 | }, 58 | }) 59 | 60 | return terraformOptions 61 | } 62 | 63 | func teamAsserter(t *testing.T, terraformOptions *terraform.Options) { 64 | // fmt.Sprint(map1) == fmt.Sprint(map2) 65 | 66 | nameOutput := terraform.Output(t, terraformOptions, "team_name") 67 | assert.Equal(t, team_name, nameOutput) 68 | 69 | // Caution here: Copy_cc comes from resource. Not the fetched data. 70 | ccOutput := terraform.Output(t, terraformOptions, "copy_cc") == "true" 71 | assert.Equal(t, team_copy_cc, ccOutput) 72 | 73 | // membersOutput := terraform.Output(t, terraformOptions, "team_members") 74 | // assert.Equal(t, createKeyValuePairs(team_members), membersOutput) 75 | 76 | } 77 | 78 | // Obtained from: https://stackoverflow.com/questions/48149969/converting-map-to-string-in-golang 79 | // func createKeyValuePairs(m map[string]string) string { 80 | // b := new(bytes.Buffer) 81 | // for key, value := range m { 82 | // fmt.Fprintf(b, "%s=\"%s\"\n", key, value) 83 | // } 84 | // return b.String() 85 | // } 86 | -------------------------------------------------------------------------------- /docs/data-sources/search_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_search_data Data Source - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_search_data (Data Source) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | data "upstash_search_data" "exampleSearchData" { 17 | id = resource.upstash_search.exampleSearchResource.id 18 | } 19 | ``` 20 | 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `id` (String) Unique Search ID for created search. 27 | 28 | ### Read-Only 29 | 30 | - `creation_time` (Number) The creation time of the search in UTC as unix timestamp. 31 | - `customer_id` (String) The unique ID associated to the owner of this search. 32 | - `endpoint` (String) Associated endpoint of your search. 33 | - `max_daily_queries` (Number) The number of maximum query operations you can perform in a day. Only query operations are included in query count. 34 | - `max_daily_updates` (Number) The number of maximum update operations you can perform in a day. Only upsert operations are included in update count. 35 | - `max_monthly_bandwidth` (Number) The maximum amount of monthly bandwidth for the search. Unit is bytes. `-1` if the limit is unlimited. 36 | - `max_query_per_second` (Number) The number of maximum query operations you can perform per second. Only query operations are included in query count. 37 | - `max_reads_per_request` (Number) The number of maximum vectors in a read operation. Query and fetch operations are included in read operations. 38 | - `max_total_metadata_size` (Number) The amount of maximum size for the total metadata sizes in your search. 39 | - `max_vector_count` (Number) The number of maximum that your search can contain. 40 | - `max_writes_per_request` (Number) The number of maximum vectors in a write operation. Only upsert operations are included in write operations. 41 | - `max_writes_per_second` (Number) The number of maximum write operations you can perform per second. Only upsert operations are included in write count. 42 | - `name` (String) Name of the search. 43 | - `read_only_token` (String, Sensitive) Readonly REST token to send request to the related search. You can't perform update operation with this token. 44 | - `region` (String) The region where your search is deployed. 45 | - `reserved_price` (Number) Monthly pricing of your search. Only available for fixed and pro plans. 46 | - `token` (String, Sensitive) REST token to send request to the related search. 47 | - `type` (String) Associated plan of the search. 48 | 49 | 50 | -------------------------------------------------------------------------------- /upstash/qstash_v2/schedule/crud.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 10 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 11 | ) 12 | 13 | func resourceScheduleRead(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 14 | c := m.(*client.UpstashClient) 15 | scheduleId := data.Get("schedule_id").(string) 16 | if scheduleId == "" { 17 | scheduleId = data.Id() 18 | } 19 | 20 | schedule, err := getSchedule(c, scheduleId) 21 | if err != nil { 22 | return diag.FromErr(err) 23 | } 24 | 25 | data.SetId("upstash-qstash-schedule-" + schedule.ScheduleId) 26 | 27 | mapping := map[string]interface{}{ 28 | "created_at": schedule.CreatedAt, 29 | "schedule_id": schedule.ScheduleId, 30 | "cron": schedule.Cron, 31 | "destination": schedule.Destination, 32 | "method": schedule.Method, 33 | "header": fmt.Sprintf("%+v", schedule.Header), 34 | "body": schedule.Body, 35 | "retries": schedule.Retries, 36 | "delay": fmt.Sprintf("%d", schedule.Delay), 37 | "callback": schedule.Callback, 38 | } 39 | 40 | return utils.SetAndCheckErrors(data, mapping) 41 | } 42 | 43 | func resourceScheduleDelete(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 44 | c := m.(*client.UpstashClient) 45 | scheduleId := data.Get("schedule_id").(string) 46 | err := deleteSchedule(c, scheduleId) 47 | if err != nil { 48 | return diag.FromErr(err) 49 | } 50 | return nil 51 | } 52 | 53 | func resourceScheduleCreate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 54 | c := m.(*client.UpstashClient) 55 | 56 | scheduleID, err := createSchedule(c, CreateQstashScheduleRequest{ 57 | Destination: data.Get("destination").(string), 58 | Body: data.Get("body").(string), 59 | ForwardHeaders: data.Get("forward_headers").(map[string]interface{}), 60 | Headers: QstashScheduleHeaders{ 61 | ContentType: data.Get("content_type").(string), 62 | Method: data.Get("method").(string), 63 | Delay: data.Get("delay").(string) + "s", 64 | Retries: data.Get("retries").(int), 65 | Callback: data.Get("callback").(string), 66 | Cron: data.Get("cron").(string), 67 | }, 68 | }) 69 | if err != nil { 70 | return diag.FromErr(err) 71 | } 72 | 73 | data.SetId("upstash-qstash-schedule-" + scheduleID) 74 | data.Set("schedule_id", scheduleID) 75 | 76 | return resourceScheduleRead(ctx, data, m) 77 | } 78 | -------------------------------------------------------------------------------- /docs/resources/search.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_search Resource - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_search (Resource) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "upstash_search" "searchResource" { 17 | name = "searchResource" 18 | region = "us-central1" 19 | type = "payg" 20 | } 21 | ``` 22 | 23 | 24 | ## Schema 25 | 26 | ### Required 27 | 28 | - `name` (String) Name of the search. 29 | - `region` (String) The region where your search is deployed. 30 | - `type` (String) Associated plan of the search. `payg` can be used 31 | 32 | ### Optional 33 | 34 | - `reserved_price` (Number) Monthly pricing of your search. Only available for fixed and pro plans. 35 | 36 | ### Read-Only 37 | 38 | - `creation_time` (Number) The creation time of the search in UTC as unix timestamp. 39 | - `customer_id` (String) The unique ID associated to the owner of this search. 40 | - `endpoint` (String) Associated endpoint of your search. 41 | - `id` (String) Unique Search ID for created search. 42 | - `max_daily_queries` (Number) The number of maximum query operations you can perform in a day. Only query operations are included in query count. 43 | - `max_daily_updates` (Number) The number of maximum update operations you can perform in a day. Only upsert operations are included in update count. 44 | - `max_monthly_bandwidth` (Number) The maximum amount of monthly bandwidth for the search. Unit is bytes. `-1` if the limit is unlimited. 45 | - `max_query_per_second` (Number) The number of maximum query operations you can perform per second. Only query operations are included in query count. 46 | - `max_reads_per_request` (Number) The number of maximum vectors in a read operation. Query and fetch operations are included in read operations. 47 | - `max_total_metadata_size` (Number) The amount of maximum size for the total metadata sizes in your search. 48 | - `max_vector_count` (Number) The number of maximum that your search can contain. 49 | - `max_writes_per_request` (Number) The number of maximum vectors in a write operation. Only upsert operations are included in write operations. 50 | - `max_writes_per_second` (Number) The number of maximum write operations you can perform per second. Only upsert operations are included in write count. 51 | - `read_only_token` (String, Sensitive) Readonly REST token to send request to the related search. You can't perform update operation with this token. 52 | - `token` (String, Sensitive) REST token to send request to the related search. 53 | 54 | 55 | -------------------------------------------------------------------------------- /upstash/qstash_v2/schedule/api_calls.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net/http" 7 | "strconv" 8 | 9 | "github.com/imroc/req" 10 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 11 | ) 12 | 13 | func getSchedule(c *client.UpstashClient, scheduleId string) (schedule QstashSchedule, err error) { 14 | 15 | resp, err := c.SendGetRequest(c.GetQstashEndpointV2()+"/schedules/"+scheduleId, "Get QStash Schedule", true) 16 | 17 | if err != nil { 18 | return schedule, err 19 | } 20 | 21 | err = resp.ToJSON(&schedule) 22 | if err != nil { 23 | return schedule, fmt.Errorf("ERR: %+v\n\n schedule:%+v\n\n resp:%+v", err, schedule, resp) 24 | } 25 | return schedule, err 26 | } 27 | 28 | func deleteSchedule(c *client.UpstashClient, scheduleId string) (err error) { 29 | return c.SendDeleteRequest(c.GetQstashEndpointV2()+"/schedules/"+scheduleId, nil, "Delete QStash Schedule", true) 30 | } 31 | 32 | func createSchedule(c *client.UpstashClient, body CreateQstashScheduleRequest) (scheduleID string, err error) { 33 | 34 | err, authorizationToken := c.GetQstashToken() 35 | if err != nil { 36 | return "", err 37 | } 38 | endpoint := c.GetQstashEndpointV2() + "/schedules/" + body.Destination 39 | 40 | postParameters := []interface{}{ 41 | req.Header{"Content-Type": body.Headers.ContentType}, 42 | req.Header{"Upstash-Method": body.Headers.Method}, 43 | req.Header{"Upstash-Delay": body.Headers.Delay}, 44 | req.Header{"Upstash-Retries": fmt.Sprint(body.Headers.Retries)}, 45 | req.Header{"Upstash-Callback": body.Headers.Callback}, 46 | req.Header{"Upstash-Cron": body.Headers.Cron}, 47 | 48 | req.Header{"Accept": "application/json"}, 49 | req.Header{"Authorization": "Bearer " + authorizationToken}, 50 | 51 | req.BodyJSON(body.Body), 52 | } 53 | 54 | forwardHeaders := body.ForwardHeaders 55 | for index := range forwardHeaders { 56 | postParameters = append(postParameters, req.Header{fmt.Sprintf("Upstash-Forward-%s", index): forwardHeaders[index].(string)}) 57 | } 58 | 59 | resp, err := req.Post( 60 | endpoint, 61 | postParameters..., 62 | ) 63 | 64 | if err != nil { 65 | return "", err 66 | } 67 | 68 | if resp.Response().StatusCode != http.StatusOK && resp.Response().StatusCode != http.StatusAccepted && resp.Response().StatusCode != http.StatusCreated { 69 | return "", errors.New("Create QStash Schedule failed, status code: " + strconv.Itoa(resp.Response().StatusCode) + " response: " + resp.String()) 70 | } 71 | 72 | var response CreateQstashScheduleResponse 73 | err = resp.ToJSON(&response) 74 | if err != nil { 75 | return scheduleID, fmt.Errorf("ERR: %+v, %+v", resp, err) 76 | } 77 | 78 | return response.ScheduleId, err 79 | } 80 | -------------------------------------------------------------------------------- /upstash/redis/database/types.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | type Database struct { 4 | DatabaseId string `json:"database_id"` 5 | DatabaseName string `json:"database_name"` 6 | Region string `json:"region"` 7 | Port int `json:"port"` 8 | CreationTime int64 `json:"creation_time"` 9 | Password string `json:"password,omitempty"` 10 | Endpoint string `json:"endpoint"` 11 | Tls bool `json:"tls"` 12 | Eviction bool `json:"eviction"` 13 | AutoUpgrade bool `json:"auto_upgrade"` 14 | ProdPack bool `json:"prod_pack_enabled"` 15 | Budget int `json:"budget"` 16 | Consistent bool `json:"consistent"` 17 | MultiZone bool `json:"multizone"` 18 | RestToken string `json:"rest_token,omitempty"` 19 | ReadOnlyRestToken string `json:"read_only_rest_token,omitempty"` 20 | DatabaseType string `json:"database_type"` 21 | State string `json:"state"` 22 | UserEmail string `json:"user_email"` 23 | DBMaxClients int `json:"db_max_clients"` 24 | DBMaxRequestSize int64 `json:"db_max_request_size"` 25 | DBDiskThreshold int64 `json:"db_disk_threshold"` 26 | DBMaxEntrySize int64 `json:"db_max_entry_size"` 27 | DBMemoryThreshold int64 `json:"db_memory_threshold"` 28 | DBDailyBandwidthLimit int64 `json:"db_daily_bandwidth_limit"` 29 | DBMaxCommandsPerSecond int64 `json:"db_max_commands_per_second"` 30 | PrimaryRegion string `json:"primary_region"` 31 | ReadRegions []string `json:"read_regions"` 32 | IpAllowList []string `json:"allowed_ip_ranges"` 33 | } 34 | 35 | type CreateDatabaseRequest struct { 36 | Region string `json:"region"` 37 | DatabaseName string `json:"database_name"` 38 | Tls bool `json:"tls"` 39 | Consistent bool `json:"consistent"` 40 | MultiZone bool `json:"multizone"` 41 | Eviction bool `json:"eviction"` 42 | AutoUpgrade bool `json:"auto_upgrade"` 43 | ProdPack bool `json:"prod_pack_enabled"` 44 | Budget int `json:"budget"` 45 | PrimaryRegion string `json:"primary_region,omitempty"` 46 | ReadRegions []string `json:"read_regions,omitempty"` 47 | } 48 | 49 | type UpdateDBBudgetRequest struct { 50 | Budget int `json:"budget"` 51 | } 52 | 53 | type UpdateDBIpAllowlistRequest struct { 54 | AllowedIps []string `json:"allowed_ips"` 55 | } 56 | 57 | type UpdateReadRegionsRequest struct { 58 | ReadRegions []string `json:"read_regions"` 59 | } 60 | -------------------------------------------------------------------------------- /integrationtesting/upstash_redis_database_test.go: -------------------------------------------------------------------------------- 1 | package integrationtesting 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/gruntwork-io/terratest/modules/terraform" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | var redis_database_name, redis_database_region string 11 | var redis_database_tls, redis_database_multizone bool 12 | 13 | func TestUpstashRedisDatabaseMAIN(t *testing.T) { 14 | t.Parallel() 15 | 16 | envVars := GetEnvVars() 17 | 18 | email = envVars.Email 19 | apikey = envVars.Apikey 20 | redis_database_name = envVars.RedisDatabaseName 21 | redis_database_region = envVars.RedisDatabaseRegion 22 | redis_database_tls = envVars.RedisDatabaseTls 23 | redis_database_multizone = envVars.RedisDatabaseMultiZone 24 | 25 | terraformOptions := redisDatabaseOptions(t) 26 | 27 | defer terraform.Destroy(t, terraformOptions) 28 | 29 | terraform.Apply(t, terraformOptions) 30 | terraform.Plan(t, terraformOptions) 31 | redisDatabaseAsserter(t, terraformOptions) 32 | 33 | UpstashRedisDatabaseRecreate(t) 34 | UpstashRedisDatabaseUpdate(t) 35 | 36 | } 37 | 38 | func UpstashRedisDatabaseRecreate(t *testing.T) { 39 | 40 | redis_database_name = redis_database_name + "Updated" 41 | redis_database_region = "us-east-1" 42 | redis_database_tls = !redis_database_tls 43 | redis_database_multizone = !redis_database_multizone 44 | 45 | terraformOptions := redisDatabaseOptions(t) 46 | terraform.Apply(t, terraformOptions) 47 | terraform.Plan(t, terraformOptions) 48 | redisDatabaseAsserter(t, terraformOptions) 49 | 50 | } 51 | 52 | func UpstashRedisDatabaseUpdate(t *testing.T) { 53 | 54 | redis_database_tls = true 55 | redis_database_multizone = true 56 | 57 | terraformOptions := redisDatabaseOptions(t) 58 | terraform.Apply(t, terraformOptions) 59 | terraform.Plan(t, terraformOptions) 60 | redisDatabaseAsserter(t, terraformOptions) 61 | 62 | } 63 | 64 | func redisDatabaseAsserter(t *testing.T, terraformOptions *terraform.Options) { 65 | databaseNameOutput := terraform.Output(t, terraformOptions, "database_name") 66 | assert.Equal(t, redis_database_name, databaseNameOutput) 67 | 68 | regionOutput := terraform.Output(t, terraformOptions, "region") 69 | assert.Equal(t, redis_database_region, regionOutput) 70 | } 71 | 72 | func redisDatabaseOptions(t *testing.T) *terraform.Options { 73 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 74 | TerraformDir: "../examples/examples/redis_database", 75 | Vars: map[string]interface{}{ 76 | "email": email, 77 | "api_key": apikey, 78 | "database_name": redis_database_name, 79 | "region": redis_database_region, 80 | "multizone": redis_database_multizone, 81 | "tls": redis_database_tls, 82 | }, 83 | }) 84 | 85 | return terraformOptions 86 | } 87 | -------------------------------------------------------------------------------- /docs/data-sources/vector_index_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_vector_index_data Data Source - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_vector_index_data (Data Source) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | data "upstash_vector_index_data" "vectorResourceData" { 17 | id = resource.upstash_vector_index.vectorResource.id 18 | } 19 | ``` 20 | 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `id` (String) Unique Index ID for created index. 27 | 28 | ### Read-Only 29 | 30 | - `creation_time` (Number) The creation time of the vector index in UTC as unix timestamp. 31 | - `customer_id` (String) The unique ID associated to the owner of this index. 32 | - `dimension_count` (Number) Size of the vector array. 33 | - `endpoint` (String) Associated endpoint of your index. 34 | - `max_daily_queries` (Number) The number of maximum query operations you can perform in a day. Only query operations are included in query count. 35 | - `max_daily_updates` (Number) The number of maximum update operations you can perform in a day. Only upsert operations are included in update count. 36 | - `max_monthly_bandwidth` (Number) The maximum amount of monthly bandwidth for the index. Unit is bytes. `-1` if the limit is unlimited. 37 | - `max_query_per_second` (Number) The number of maximum query operations you can perform per second. Only query operations are included in query count. 38 | - `max_reads_per_request` (Number) The number of maximum vectors in a read operation. Query and fetch operations are included in read operations. 39 | - `max_total_metadata_size` (Number) The amount of maximum size for the total metadata sizes in your index. 40 | - `max_vector_count` (Number) The number of maximum that your index can contain. 41 | - `max_writes_per_request` (Number) The number of maximum vectors in a write operation. Only upsert operations are included in write operations. 42 | - `max_writes_per_second` (Number) The number of maximum write operations you can perform per second. Only upsert operations are included in write count. 43 | - `name` (String) Name of the index. 44 | - `read_only_token` (String, Sensitive) Readonly REST token to send request to the related index. You can't perform update operation with this token. 45 | - `region` (String) The region where your index is deployed. 46 | - `reserved_price` (Number) Monthly pricing of your index. Only available for fixed and pro plans. 47 | - `similarity_function` (String) Associated distance metric to calculate the similarity. 48 | - `token` (String, Sensitive) REST token to send request to the related index. 49 | - `type` (String) Associated plan of the index. Either `free`, `paid`, `fixed` or `pro`. 50 | 51 | 52 | -------------------------------------------------------------------------------- /upstash/qstash/schedule/api_calls.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "net/http" 7 | "strconv" 8 | 9 | "github.com/imroc/req" 10 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 11 | ) 12 | 13 | func getSchedule(c *client.UpstashClient, scheduleId string) (schedule QstashSchedule, err error) { 14 | 15 | resp, err := c.SendGetRequest(c.GetQstashEndpoint()+"/schedules/"+scheduleId, "Get QStash Schedule", true) 16 | 17 | if err != nil { 18 | return schedule, err 19 | } 20 | 21 | err = resp.ToJSON(&schedule) 22 | 23 | if err != nil { 24 | return schedule, fmt.Errorf("ERR: %+v\n\n schedule:%+v\n\n resp:%+v", err, schedule, resp) 25 | } 26 | return schedule, err 27 | } 28 | 29 | func createSchedule(c *client.UpstashClient, body CreateQstashScheduleRequest) (schedule QstashSchedule, err error) { 30 | 31 | err, authorizationToken := c.GetQstashToken() 32 | if err != nil { 33 | return schedule, err 34 | } 35 | endpoint := c.GetQstashEndpoint() + "/publish/" + body.Destination 36 | 37 | postParameters := []interface{}{ 38 | req.Header{"Upstash-Cron": body.Headers.Cron}, 39 | req.Header{"Upstash-Retries": fmt.Sprint(body.Headers.Retries)}, 40 | req.Header{"Accept": "application/json"}, 41 | req.Header{"Authorization": "Bearer " + authorizationToken}, 42 | req.Header{"Content-Type": body.Headers.ContentType}, 43 | req.Header{"Upstash-Deduplication-Id": body.Headers.DeduplicationId}, 44 | req.Header{"Upstash-Content-Based-Deduplication": fmt.Sprint(body.Headers.ContentBasedDeduplication)}, 45 | req.Header{"Upstash-NotBefore": fmt.Sprint(body.Headers.NotBefore)}, 46 | req.Header{"Upstash-Delay": body.Headers.Delay}, 47 | req.Header{"Upstash-Callback": body.Headers.Callback}, 48 | req.BodyJSON(body.Body), 49 | } 50 | 51 | forwardHeaders := body.ForwardHeaders 52 | for index := range forwardHeaders { 53 | postParameters = append(postParameters, req.Header{fmt.Sprintf("Upstash-Forward-%s", index): forwardHeaders[index].(string)}) 54 | } 55 | 56 | resp, err := req.Post( 57 | endpoint, 58 | postParameters..., 59 | ) 60 | 61 | if err != nil { 62 | return schedule, err 63 | } 64 | 65 | if resp.Response().StatusCode != http.StatusOK && resp.Response().StatusCode != http.StatusAccepted && resp.Response().StatusCode != http.StatusCreated { 66 | return schedule, errors.New("Create QStash Schedule failed, status code: " + strconv.Itoa(resp.Response().StatusCode) + " response: " + resp.String()) 67 | } 68 | 69 | err = resp.ToJSON(&schedule) 70 | if err != nil { 71 | return schedule, fmt.Errorf("ERR: %+v, %+v", resp, err) 72 | } 73 | return schedule, err 74 | } 75 | 76 | func deleteSchedule(c *client.UpstashClient, scheduleId string) (err error) { 77 | return c.SendDeleteRequest(c.GetQstashEndpoint()+"/schedules/"+scheduleId, nil, "Delete QStash Schedule", true) 78 | } 79 | -------------------------------------------------------------------------------- /docs/data-sources/redis_database_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_redis_database_data Data Source - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_redis_database_data (Data Source) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | data "upstash_redis_database_data" "exampleDBData" { 17 | database_id = resource.upstash_redis_database.exampleDB.database_id 18 | } 19 | ``` 20 | 21 | 22 | ## Schema 23 | 24 | ### Required 25 | 26 | - `database_id` (String) Unique Database ID for requested database 27 | 28 | ### Read-Only 29 | 30 | - `auto_scale` (Boolean) Upgrade to higher plans automatically when it hits quotas 31 | - `budget` (Number) Budget for the database. It is used to limit the cost of the database. If the budget is reached, the database will be throttled until the next month. 32 | - `consistent` (Boolean, Deprecated) When enabled database runs in Consistency Mode 33 | - `creation_time` (Number) Creation time of the database 34 | - `database_name` (String) Name of the database 35 | - `database_type` (String) Type of the database 36 | - `db_daily_bandwidth_limit` (Number) Daily bandwidth limit for the database 37 | - `db_disk_threshold` (Number) Disk threshold for the database 38 | - `db_max_clients` (Number) Max clients for the database 39 | - `db_max_commands_per_second` (Number) Max commands per second for the database 40 | - `db_max_entry_size` (Number) Max entry size for the database 41 | - `db_max_request_size` (Number) Max request size for the database 42 | - `db_memory_threshold` (Number) Memory threshold for the database 43 | - `endpoint` (String) Database URL for connection 44 | - `eviction` (Boolean) Enable eviction, to evict keys when your database reaches the max size 45 | - `id` (String) The ID of this resource. 46 | - `ip_allowlist` (Set of String) Ip CIDR allowlist for the database. If not set, all IPs are allowed to connect to the database. 47 | - `multizone` (Boolean, Deprecated) When enabled database is highly available and deployed multi-zone 48 | - `password` (String, Sensitive) Password of the database 49 | - `port` (Number) Port of the endpoint 50 | - `primary_region` (String) Primary region for the database 51 | - `prod_pack` (Boolean) Whether Prod Pack is enabled for the database. 52 | - `read_only_rest_token` (String, Sensitive) Rest Token for the database. 53 | - `read_regions` (Set of String) Read regions for the database 54 | - `region` (String) Region of the database. For globals, check for primary_region and read_regions fields 55 | - `rest_token` (String, Sensitive) Rest Token for the database. 56 | - `state` (String) State of the database 57 | - `tls` (Boolean, Deprecated) When enabled, data is encrypted in transit. 58 | - `user_email` (String) User email for the database 59 | 60 | 61 | -------------------------------------------------------------------------------- /upstash/qstash_v2/schedule/resource.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func ResourceQstashSchedule() *schema.Resource { 8 | return &schema.Resource{ 9 | CreateContext: resourceScheduleCreate, 10 | ReadContext: resourceScheduleRead, 11 | DeleteContext: resourceScheduleDelete, 12 | Schema: map[string]*schema.Schema{ 13 | "created_at": { 14 | Type: schema.TypeInt, 15 | Computed: true, 16 | Description: "Creation time for Qstash Schedule.", 17 | }, 18 | "schedule_id": { 19 | Type: schema.TypeString, 20 | Computed: true, 21 | Description: "Unique Qstash Schedule ID for requested schedule", 22 | }, 23 | "cron": { 24 | Type: schema.TypeString, 25 | Required: true, 26 | ForceNew: true, 27 | Description: "Cron string for Qstash Schedule", 28 | }, 29 | "destination": { 30 | Type: schema.TypeString, 31 | Required: true, 32 | ForceNew: true, 33 | Description: "Destination for Qstash Schedule. Either Topic Name or valid URL", 34 | }, 35 | "method": { 36 | Type: schema.TypeString, 37 | Optional: true, 38 | ForceNew: true, 39 | Description: "Method of Http Request on QStash", 40 | }, 41 | "header": { 42 | Type: schema.TypeString, 43 | Computed: true, 44 | Description: "Headers for the QStash schedule", 45 | }, 46 | "body": { 47 | Type: schema.TypeString, 48 | ForceNew: true, 49 | Optional: true, 50 | Description: "Body to send for the POST request in string format. Needs escaping (\\) double quotes.", 51 | }, 52 | "retries": { 53 | Type: schema.TypeInt, 54 | ForceNew: true, 55 | Optional: true, 56 | Default: 3, 57 | Description: "Retries for Qstash Schedule requests.", 58 | }, 59 | "delay": { 60 | Type: schema.TypeString, 61 | ForceNew: true, 62 | Optional: true, 63 | Default: "0", 64 | Description: "Delay for Qstash Schedule. Delay should be given in seconds", 65 | }, 66 | "callback": { 67 | Type: schema.TypeString, 68 | ForceNew: true, 69 | Optional: true, 70 | Description: "Callback URL for Qstash Schedule.", 71 | }, 72 | "forward_headers": { 73 | Type: schema.TypeMap, 74 | ForceNew: true, 75 | Optional: true, 76 | Elem: &schema.Schema{ 77 | Type: schema.TypeString, 78 | }, 79 | Description: "Forward headers to your API", 80 | }, 81 | "content_type": { 82 | Type: schema.TypeString, 83 | Optional: true, 84 | ForceNew: true, 85 | Description: "Content type for Qstash Scheduling.", 86 | }, 87 | }, 88 | Importer: &schema.ResourceImporter{ 89 | StateContext: schema.ImportStatePassthroughContext, 90 | }, 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /upstash/qstash/schedule/crud.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 9 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 10 | ) 11 | 12 | func resourceScheduleRead(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 13 | c := m.(*client.UpstashClient) 14 | scheduleId := data.Get("schedule_id").(string) 15 | if scheduleId == "" { 16 | scheduleId = data.Id() 17 | } 18 | 19 | schedule, err := getSchedule(c, scheduleId) 20 | if err != nil { 21 | return diag.FromErr(err) 22 | } 23 | 24 | data.SetId("upstash-qstash-schedule-" + schedule.ScheduleId) 25 | 26 | destination := schedule.Destination.Topic.TopicId 27 | if schedule.Destination.Type == "url" { 28 | destination = schedule.Destination.Url 29 | } 30 | mapping := map[string]interface{}{ 31 | "created_at": schedule.CreatedAt, 32 | "retries": schedule.Settings.Retries, 33 | "not_before": schedule.Settings.NotBefore, 34 | "cron": schedule.Cron, 35 | "destination": destination, 36 | "schedule_id": schedule.ScheduleId, 37 | } 38 | 39 | return utils.SetAndCheckErrors(data, mapping) 40 | } 41 | 42 | func resourceScheduleCreate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 43 | c := m.(*client.UpstashClient) 44 | 45 | schedule, err := createSchedule(c, CreateQstashScheduleRequest{ 46 | Destination: data.Get("destination").(string), 47 | Body: data.Get("body").(string), 48 | ForwardHeaders: data.Get("forward_headers").(map[string]interface{}), 49 | Headers: QstashScheduleHeaders{ 50 | ContentType: data.Get("content_type").(string), 51 | DeduplicationId: data.Get("deduplication_id").(string), 52 | ContentBasedDeduplication: data.Get("content_based_deduplication").(bool), 53 | NotBefore: data.Get("not_before").(int), 54 | Delay: data.Get("delay").(string), 55 | Callback: data.Get("callback").(string), 56 | Retries: data.Get("retries").(int), 57 | Cron: data.Get("cron").(string), 58 | }, 59 | }, 60 | ) 61 | if err != nil { 62 | return diag.FromErr(err) 63 | } 64 | 65 | data.SetId("upstash-qstash-schedule-" + schedule.ScheduleId) 66 | data.Set("schedule_id", schedule.ScheduleId) 67 | 68 | return resourceScheduleRead(ctx, data, m) 69 | } 70 | 71 | func resourceScheduleDelete(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 72 | c := m.(*client.UpstashClient) 73 | scheduleId := data.Get("schedule_id").(string) 74 | err := deleteSchedule(c, scheduleId) 75 | if err != nil { 76 | return diag.FromErr(err) 77 | } 78 | return nil 79 | } 80 | -------------------------------------------------------------------------------- /docs/resources/vector_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_vector_index Resource - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_vector_index (Resource) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "upstash_vector_index" "vectorResource" { 17 | name = "vectorResource" 18 | similarity_function = "COSINE" 19 | dimension_count = 1536 20 | region = "us-east-1" 21 | type = "fixed" 22 | } 23 | ``` 24 | 25 | 26 | ## Schema 27 | 28 | ### Required 29 | 30 | - `dimension_count` (Number) Size of the vector array. 31 | - `name` (String) Name of the index. 32 | - `region` (String) The region where your index is deployed. 33 | - `similarity_function` (String) Associated distance metric to calculate the similarity. 34 | - `type` (String) Associated plan of the index. Either `free`, `paid`, `fixed` or `pro`. 35 | 36 | ### Optional 37 | 38 | - `reserved_price` (Number) Monthly pricing of your index. Only available for fixed and pro plans. 39 | 40 | ### Read-Only 41 | 42 | - `creation_time` (Number) The creation time of the vector index in UTC as unix timestamp. 43 | - `customer_id` (String) The unique ID associated to the owner of this index. 44 | - `endpoint` (String) Associated endpoint of your index. 45 | - `id` (String) Unique Index ID for created index. 46 | - `max_daily_queries` (Number) The number of maximum query operations you can perform in a day. Only query operations are included in query count. 47 | - `max_daily_updates` (Number) The number of maximum update operations you can perform in a day. Only upsert operations are included in update count. 48 | - `max_monthly_bandwidth` (Number) The maximum amount of monthly bandwidth for the index. Unit is bytes. `-1` if the limit is unlimited. 49 | - `max_query_per_second` (Number) The number of maximum query operations you can perform per second. Only query operations are included in query count. 50 | - `max_reads_per_request` (Number) The number of maximum vectors in a read operation. Query and fetch operations are included in read operations. 51 | - `max_total_metadata_size` (Number) The amount of maximum size for the total metadata sizes in your index. 52 | - `max_vector_count` (Number) The number of maximum that your index can contain. 53 | - `max_writes_per_request` (Number) The number of maximum vectors in a write operation. Only upsert operations are included in write operations. 54 | - `max_writes_per_second` (Number) The number of maximum write operations you can perform per second. Only upsert operations are included in write count. 55 | - `read_only_token` (String, Sensitive) Readonly REST token to send request to the related index. You can't perform update operation with this token. 56 | - `token` (String, Sensitive) REST token to send request to the related index. 57 | 58 | 59 | -------------------------------------------------------------------------------- /upstash/qstash/schedule/resource.go: -------------------------------------------------------------------------------- 1 | package schedule 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func ResourceQstashSchedule() *schema.Resource { 8 | return &schema.Resource{ 9 | CreateContext: resourceScheduleCreate, 10 | ReadContext: resourceScheduleRead, 11 | DeleteContext: resourceScheduleDelete, 12 | Schema: map[string]*schema.Schema{ 13 | "schedule_id": { 14 | Type: schema.TypeString, 15 | Computed: true, 16 | Description: "Unique Qstash Schedule ID for requested schedule", 17 | }, 18 | "body": { 19 | Type: schema.TypeString, 20 | ForceNew: true, 21 | Optional: true, 22 | Description: "Body to send for the POST request in string format. Needs escaping (\\) double quotes.", 23 | }, 24 | "cron": { 25 | Type: schema.TypeString, 26 | Required: true, 27 | ForceNew: true, 28 | Description: "Cron string for Qstash Schedule", 29 | }, 30 | "destination": { 31 | Type: schema.TypeString, 32 | Required: true, 33 | ForceNew: true, 34 | Description: "Destination for Qstash Schedule. Either Topic ID or valid URL", 35 | }, 36 | "content_type": { 37 | Type: schema.TypeString, 38 | Optional: true, 39 | ForceNew: true, 40 | Description: "Content type for Qstash Scheduling.", 41 | }, 42 | "deduplication_id": { 43 | Type: schema.TypeString, 44 | ForceNew: true, 45 | Optional: true, 46 | Description: "Deduplication ID for Qstash Scheduling.", 47 | }, 48 | "content_based_deduplication": { 49 | Type: schema.TypeBool, 50 | ForceNew: true, 51 | Optional: true, 52 | Description: "Content Based Deduplication (bool) for Qstash Scheduling.", 53 | }, 54 | "not_before": { 55 | Type: schema.TypeInt, 56 | ForceNew: true, 57 | Optional: true, 58 | Description: "Start time for Qstash Scheduling.", 59 | }, 60 | "delay": { 61 | Type: schema.TypeString, 62 | ForceNew: true, 63 | Optional: true, 64 | Description: "Delay for Qstash Schedule.", 65 | }, 66 | "callback": { 67 | Type: schema.TypeString, 68 | ForceNew: true, 69 | Optional: true, 70 | Description: "Callback URL for Qstash Schedule.", 71 | }, 72 | "retries": { 73 | Type: schema.TypeInt, 74 | ForceNew: true, 75 | Optional: true, 76 | Default: 3, 77 | Description: "Retries for Qstash Schedule requests.", 78 | }, 79 | "created_at": { 80 | Type: schema.TypeInt, 81 | Computed: true, 82 | Description: "Creation time for Qstash Schedule.", 83 | }, 84 | "forward_headers": { 85 | Type: schema.TypeMap, 86 | ForceNew: true, 87 | Optional: true, 88 | Elem: &schema.Schema{ 89 | Type: schema.TypeString, 90 | }, 91 | Description: "Forward headers to your API", 92 | }, 93 | }, 94 | Importer: &schema.ResourceImporter{ 95 | StateContext: schema.ImportStatePassthroughContext, 96 | }, 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /examples/examples/redis_database/outputs.tf: -------------------------------------------------------------------------------- 1 | 2 | output "database_name" { 3 | value = data.upstash_redis_database_data.exampleDBData.database_name 4 | } 5 | 6 | output "region" { 7 | value = data.upstash_redis_database_data.exampleDBData.region 8 | } 9 | 10 | output "multizone" { 11 | value = resource.upstash_redis_database.exampleDB.multizone 12 | } 13 | 14 | output "DBEndpoint" { 15 | value = data.upstash_redis_database_data.exampleDBData.endpoint 16 | } 17 | 18 | output "endpoint" { 19 | value = resource.upstash_redis_database.exampleDB.endpoint 20 | } 21 | 22 | output "db_name" { 23 | value = resource.upstash_redis_database.exampleDB.database_name 24 | } 25 | 26 | output "password" { 27 | value = resource.upstash_redis_database.exampleDB 28 | sensitive = true 29 | } 30 | 31 | output "port" { 32 | value = data.upstash_redis_database_data.exampleDBData.port 33 | } 34 | 35 | output "rest_token" { 36 | value = data.upstash_redis_database_data.exampleDBData.rest_token 37 | sensitive = true 38 | } 39 | 40 | output "read_only_rest_token" { 41 | value = data.upstash_redis_database_data.exampleDBData.read_only_rest_token 42 | sensitive = true 43 | } 44 | 45 | output "creation_time" { 46 | value = data.upstash_redis_database_data.exampleDBData.creation_time 47 | } 48 | 49 | output "database_type" { 50 | value = data.upstash_redis_database_data.exampleDBData.database_type 51 | } 52 | 53 | output "state" { 54 | value = data.upstash_redis_database_data.exampleDBData.state 55 | } 56 | 57 | output "user_email" { 58 | value = data.upstash_redis_database_data.exampleDBData.user_email 59 | } 60 | 61 | output "db_max_clients" { 62 | value = data.upstash_redis_database_data.exampleDBData.db_max_clients 63 | } 64 | 65 | output "db_max_request_size" { 66 | value = data.upstash_redis_database_data.exampleDBData.db_max_request_size 67 | } 68 | 69 | output "db_disk_threshold" { 70 | value = data.upstash_redis_database_data.exampleDBData.db_disk_threshold 71 | } 72 | 73 | output "db_max_entry_size" { 74 | value = data.upstash_redis_database_data.exampleDBData.db_max_entry_size 75 | } 76 | 77 | output "db_memory_threshold" { 78 | value = data.upstash_redis_database_data.exampleDBData.db_memory_threshold 79 | } 80 | 81 | output "db_daily_bandwidth_limit" { 82 | value = data.upstash_redis_database_data.exampleDBData.db_daily_bandwidth_limit 83 | } 84 | 85 | output "db_max_commands_per_second" { 86 | value = data.upstash_redis_database_data.exampleDBData.db_max_commands_per_second 87 | } 88 | 89 | output "tls" { 90 | value = data.upstash_redis_database_data.exampleDBData.tls 91 | } 92 | 93 | output "consistent" { 94 | value = data.upstash_redis_database_data.exampleDBData.consistent 95 | } 96 | 97 | output "primary_region" { 98 | value = data.upstash_redis_database_data.exampleDBData.primary_region 99 | } 100 | 101 | output "read_regions" { 102 | value = data.upstash_redis_database_data.exampleDBData.read_regions 103 | } 104 | output "ip_allowlist" { 105 | value = data.upstash_redis_database_data.exampleDBData.ip_allowlist 106 | } 107 | -------------------------------------------------------------------------------- /upstash/provider.go: -------------------------------------------------------------------------------- 1 | package upstash 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/upstash/terraform-provider-upstash/v2/upstash/search" 7 | "github.com/upstash/terraform-provider-upstash/v2/upstash/vector/index" 8 | 9 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 10 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 11 | qstashEndpoint "github.com/upstash/terraform-provider-upstash/v2/upstash/qstash/endpoint" 12 | qstashSchedule "github.com/upstash/terraform-provider-upstash/v2/upstash/qstash/schedule" 13 | qstashTopic "github.com/upstash/terraform-provider-upstash/v2/upstash/qstash/topic" 14 | qstashScheduleV2 "github.com/upstash/terraform-provider-upstash/v2/upstash/qstash_v2/schedule" 15 | qstashTopicV2 "github.com/upstash/terraform-provider-upstash/v2/upstash/qstash_v2/topic" 16 | 17 | "github.com/upstash/terraform-provider-upstash/v2/upstash/redis/database" 18 | "github.com/upstash/terraform-provider-upstash/v2/upstash/team" 19 | 20 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 21 | ) 22 | 23 | // Provider - 24 | func Provider() *schema.Provider { 25 | return &schema.Provider{ 26 | Schema: map[string]*schema.Schema{ 27 | "email": { 28 | Type: schema.TypeString, 29 | Required: true, 30 | DefaultFunc: schema.EnvDefaultFunc("UPSTASH_EMAIL", nil), 31 | }, 32 | "api_key": { 33 | Type: schema.TypeString, 34 | Required: true, 35 | Sensitive: true, 36 | DefaultFunc: schema.EnvDefaultFunc("UPSTASH_API_KEY", nil), 37 | }, 38 | }, 39 | ResourcesMap: map[string]*schema.Resource{ 40 | "upstash_redis_database": database.ResourceDatabase(), 41 | "upstash_vector_index": index.ResourceIndex(), 42 | "upstash_search": search.ResourceSearch(), 43 | "upstash_team": team.ResourceTeam(), 44 | "upstash_qstash_topic": qstashTopic.ResourceQstashTopic(), 45 | "upstash_qstash_endpoint": qstashEndpoint.ResourceQstashEndpoint(), 46 | "upstash_qstash_schedule": qstashSchedule.ResourceQstashSchedule(), 47 | "upstash_qstash_topic_v2": qstashTopicV2.ResourceQstashTopic(), 48 | "upstash_qstash_schedule_v2": qstashScheduleV2.ResourceQstashSchedule(), 49 | }, 50 | DataSourcesMap: map[string]*schema.Resource{ 51 | "upstash_redis_database_data": database.DataSourceDatabase(), 52 | "upstash_vector_index_data": index.DataResourceIndex(), 53 | "upstash_search_data": search.DataResourceSearch(), 54 | "upstash_team_data": team.DataSourceTeam(), 55 | "upstash_qstash_topic_data": qstashTopic.DataSourceQstashTopic(), 56 | "upstash_qstash_endpoint_data": qstashEndpoint.DataSourceQstashEndpoint(), 57 | "upstash_qstash_schedule_data": qstashSchedule.DataSourceQstashSchedule(), 58 | "upstash_qstash_topic_v2_data": qstashTopicV2.DataSourceQstashTopic(), 59 | "upstash_qstash_schedule_v2_data": qstashScheduleV2.DataSourceQstashSchedule(), 60 | }, 61 | ConfigureContextFunc: providerConfigure, 62 | } 63 | } 64 | 65 | func providerConfigure(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) { 66 | username := d.Get("email").(string) 67 | password := d.Get("api_key").(string) 68 | 69 | c := client.NewUpstashClient(username, password) 70 | return c, nil 71 | } 72 | -------------------------------------------------------------------------------- /upstash/team/crud.go: -------------------------------------------------------------------------------- 1 | package team 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 9 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 10 | ) 11 | 12 | func resourceCreate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 13 | c := m.(*client.UpstashClient) 14 | team, err := createTeam(c, CreateTeamRequest{ 15 | TeamName: data.Get("team_name").(string), 16 | CopyCC: data.Get("copy_cc").(bool), 17 | }) 18 | if err != nil { 19 | return diag.FromErr(err) 20 | } 21 | data.SetId("upstash-team-" + team.TeamId) 22 | data.Set("team_id", team.TeamId) 23 | 24 | return resourceUpdate(ctx, data, m) 25 | // return resourceRead(ctx, data, m) 26 | } 27 | 28 | func resourceRead(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 29 | c := m.(*client.UpstashClient) 30 | teamId := data.Get("team_id").(string) 31 | if teamId == "" { 32 | teamId = data.Id() 33 | } 34 | teamMembers, err := getTeamMembers(c, teamId) 35 | 36 | teamName := teamMembers[0].TeamName 37 | 38 | membersMap := make(map[string]string) 39 | 40 | var copycc bool 41 | for i := 0; i < len(teamMembers); i++ { 42 | membersMap[teamMembers[i].MemberEmail] = teamMembers[i].MemberRole 43 | if teamMembers[i].CopyCC { 44 | copycc = teamMembers[i].CopyCC 45 | } 46 | } 47 | 48 | if err != nil { 49 | return diag.FromErr(err) 50 | } 51 | 52 | data.SetId("upstash-team-" + teamId) 53 | 54 | mapping := map[string]interface{}{ 55 | "team_id": teamId, 56 | "team_name": teamName, 57 | "team_members": membersMap, 58 | "copy_cc": copycc, 59 | } 60 | 61 | return utils.SetAndCheckErrors(data, mapping) 62 | 63 | } 64 | 65 | func resourceUpdate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 66 | c := m.(*client.UpstashClient) 67 | teamId := data.Get("team_id").(string) 68 | 69 | // Only members can change, what to do in that case? 70 | if data.HasChange("team_members") { 71 | 72 | a, b := data.GetChange("team_members") 73 | old := a.(map[string]interface{}) 74 | new := b.(map[string]interface{}) 75 | 76 | for email, role := range old { 77 | if role.(string) != "owner" { 78 | if role.(string) != new[email] { 79 | err := removeMember(c, teamId, email) 80 | if err != nil { 81 | return diag.FromErr(err) 82 | } 83 | } 84 | } 85 | } 86 | 87 | for email, role := range new { 88 | if role.(string) != "owner" { 89 | if role.(string) != old[email] { 90 | err := addMember(c, teamId, email, role.(string)) 91 | if err != nil { 92 | return diag.FromErr(err) 93 | } 94 | } 95 | } 96 | } 97 | } 98 | 99 | return resourceRead(ctx, data, m) 100 | } 101 | 102 | func resourceDelete(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 103 | c := m.(*client.UpstashClient) 104 | teamId := data.Get("team_id").(string) 105 | err := deleteTeam(c, teamId) 106 | 107 | if err != nil { 108 | return diag.FromErr(err) 109 | } 110 | return nil 111 | } 112 | -------------------------------------------------------------------------------- /upstash/redis/database/api_calls.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "strings" 5 | 6 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 7 | ) 8 | 9 | // not needed if changes 10 | 11 | func CreateDatabase(c *client.UpstashClient, body CreateDatabaseRequest) (database Database, err error) { 12 | resp, err := c.SendPostRequest("/v2/redis/database", body, "Create Redis Database", false) 13 | if err != nil { 14 | return database, err 15 | } 16 | 17 | err = resp.ToJSON(&database) 18 | return database, err 19 | } 20 | 21 | func GetDatabase(c *client.UpstashClient, databaseId string) (database Database, err error) { 22 | resp, err := c.SendGetRequest("/v2/redis/database/"+databaseId, "Get Redis Database", false) 23 | if err != nil { 24 | return database, err 25 | } 26 | 27 | err = resp.ToJSON(&database) 28 | return database, err 29 | } 30 | 31 | func UpdateReadRegions(c *client.UpstashClient, databaseId string, readRegions UpdateReadRegionsRequest) (err error) { 32 | _, err = c.SendPostRequest("/v2/redis/update-regions/"+databaseId, readRegions, "Update Regions for Redis Database", false) 33 | return err 34 | } 35 | 36 | func EnableTLS(c *client.UpstashClient, databaseId string) (err error) { 37 | _, err = c.SendPostRequest("/v2/redis/enable-tls/"+databaseId, nil, "Enable Tls for Redis Database", false) 38 | return err 39 | } 40 | 41 | func ConfigureEviction(c *client.UpstashClient, databaseId string, enabled bool) (err error) { 42 | path := "/v2/redis/" 43 | if enabled { 44 | path += "enable-eviction/" 45 | } else { 46 | path += "disable-eviction/" 47 | } 48 | path += databaseId 49 | 50 | _, err = c.SendPostRequest(path, nil, "Configure Eviction Redis Database", false) 51 | 52 | return err 53 | } 54 | 55 | func ConfigureAutoUpgrade(c *client.UpstashClient, databaseId string, enabled bool) (err error) { 56 | path := "/v2/redis/" 57 | if enabled { 58 | path += "enable-autoupgrade/" 59 | } else { 60 | path += "disable-autoupgrade/" 61 | } 62 | path += databaseId 63 | _, err = c.SendPostRequest(path, nil, "Configure Auto Upgrade for Redis Database", false) 64 | 65 | if err != nil && (strings.Contains(err.Error(), "already enabled") || strings.Contains(err.Error(), "already disabled")) { 66 | return nil 67 | } 68 | return err 69 | } 70 | 71 | func ConfigureProdPack(c *client.UpstashClient, databaseId string, enabled bool) (err error) { 72 | path := "/v2/redis/" 73 | if enabled { 74 | path += "enable-prodpack/" 75 | } else { 76 | path += "disable-prodpack/" 77 | } 78 | path += databaseId 79 | _, err = c.SendPostRequest(path, nil, "Configure Prod Pack for Redis Database", false) 80 | 81 | return err 82 | } 83 | 84 | func UpdateDBBudget(c *client.UpstashClient, databaseId string, budgetBody UpdateDBBudgetRequest) (err error) { 85 | _, err = c.SendPatchRequest("/v2/redis/update-budget/"+databaseId, budgetBody, "Update Redis Database Budget", false) 86 | return err 87 | } 88 | func UpdateDBIpAllowlist(c *client.UpstashClient, databaseId string, body UpdateDBIpAllowlistRequest) (err error) { 89 | _, err = c.SendPostRequest("/v2/redis/update-allowlist/"+databaseId, body, "Update Redis Database Ip Allowlist", false) 90 | return err 91 | } 92 | 93 | func DeleteDatabase(c *client.UpstashClient, databaseId string) (err error) { 94 | return c.SendDeleteRequest("/v2/redis/database/"+databaseId, nil, "Delete Redis Database", false) 95 | } 96 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/upstash/terraform-provider-upstash/v2 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/gruntwork-io/terratest v0.50.0 7 | github.com/hashicorp/terraform-plugin-sdk/v2 v2.37.0 8 | github.com/imroc/req v0.3.0 9 | github.com/stretchr/testify v1.10.0 10 | ) 11 | 12 | require ( 13 | github.com/agext/levenshtein v1.2.3 // indirect 14 | github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect 15 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 16 | github.com/davecgh/go-spew v1.1.1 // indirect 17 | github.com/fatih/color v1.16.0 // indirect 18 | github.com/golang/protobuf v1.5.4 // indirect 19 | github.com/google/go-cmp v0.7.0 // indirect 20 | github.com/hashicorp/errwrap v1.0.0 // indirect 21 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 22 | github.com/hashicorp/go-cty v1.5.0 // indirect 23 | github.com/hashicorp/go-getter/v2 v2.2.3 // indirect 24 | github.com/hashicorp/go-hclog v1.6.3 // indirect 25 | github.com/hashicorp/go-multierror v1.1.1 // indirect 26 | github.com/hashicorp/go-plugin v1.6.3 // indirect 27 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 28 | github.com/hashicorp/go-uuid v1.0.3 // indirect 29 | github.com/hashicorp/go-version v1.7.0 // indirect 30 | github.com/hashicorp/hcl/v2 v2.23.0 // indirect 31 | github.com/hashicorp/logutils v1.0.0 // indirect 32 | github.com/hashicorp/terraform-json v0.25.0 // indirect 33 | github.com/hashicorp/terraform-plugin-go v0.27.0 // indirect 34 | github.com/hashicorp/terraform-plugin-log v0.9.0 // indirect 35 | github.com/hashicorp/terraform-registry-address v0.2.5 // indirect 36 | github.com/hashicorp/terraform-svchost v0.1.1 // indirect 37 | github.com/hashicorp/yamux v0.1.1 // indirect 38 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 39 | github.com/klauspost/compress v1.16.5 // indirect 40 | github.com/kr/pretty v0.3.0 // indirect 41 | github.com/mattn/go-colorable v0.1.13 // indirect 42 | github.com/mattn/go-isatty v0.0.20 // indirect 43 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 44 | github.com/mitchellh/copystructure v1.2.0 // indirect 45 | github.com/mitchellh/go-homedir v1.1.0 // indirect 46 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 47 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 48 | github.com/mitchellh/mapstructure v1.5.0 // indirect 49 | github.com/mitchellh/reflectwalk v1.0.2 // indirect 50 | github.com/oklog/run v1.0.0 // indirect 51 | github.com/pmezard/go-difflib v1.0.0 // indirect 52 | github.com/rogpeppe/go-internal v1.9.0 // indirect 53 | github.com/tmccombs/hcl2json v0.6.4 // indirect 54 | github.com/ulikunitz/xz v0.5.10 // indirect 55 | github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect 56 | github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect 57 | github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect 58 | github.com/zclconf/go-cty v1.16.2 // indirect 59 | golang.org/x/crypto v0.38.0 // indirect 60 | golang.org/x/mod v0.24.0 // indirect 61 | golang.org/x/net v0.39.0 // indirect 62 | golang.org/x/sync v0.14.0 // indirect 63 | golang.org/x/sys v0.33.0 // indirect 64 | golang.org/x/text v0.25.0 // indirect 65 | golang.org/x/tools v0.22.0 // indirect 66 | google.golang.org/appengine v1.6.8 // indirect 67 | google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect 68 | google.golang.org/grpc v1.72.1 // indirect 69 | google.golang.org/protobuf v1.36.6 // indirect 70 | gopkg.in/yaml.v3 v3.0.1 // indirect 71 | ) 72 | -------------------------------------------------------------------------------- /docs/resources/redis_database.md: -------------------------------------------------------------------------------- 1 | --- 2 | # generated by https://github.com/hashicorp/terraform-plugin-docs 3 | page_title: "upstash_redis_database Resource - terraform-provider-upstash" 4 | subcategory: "" 5 | description: |- 6 | 7 | --- 8 | 9 | # upstash_redis_database (Resource) 10 | 11 | 12 | 13 | ## Example Usage 14 | 15 | ```terraform 16 | resource "upstash_redis_database" "exampleDB" { 17 | database_name = "Terraform DB6" 18 | region = "global" 19 | primary_region = "eu-west-1" 20 | tls = true 21 | } 22 | ``` 23 | 24 | 25 | ## Schema 26 | 27 | ### Required 28 | 29 | - `database_name` (String) Name of the database 30 | - `region` (String) Region of the database. For global gcp regions, use `gcp-global`. For globals, check for primary_region and read_regions fields 31 | 32 | ### Optional 33 | 34 | - `auto_scale` (Boolean) Upgrade to higher plans automatically when it hits quotas 35 | - `budget` (Number) Budget for the database (default $20). It is used to limit the cost of the database. If the budget is reached, the database will be throttled until the next month. 36 | - `consistent` (Boolean, Deprecated) When enabled, all writes are synchronously persisted to the disk. 37 | - `eviction` (Boolean) Enable eviction, to evict keys when your database reaches the max size 38 | - `ip_allowlist` (Set of String) Ip CIDR allowlist for the database. If not set, all IPs are allowed to connect to the database. 39 | - `multizone` (Boolean, Deprecated) When enabled, database becomes highly available and is deployed in multiple zones. (If changed to false from true, results in deletion and recreation of the resource) 40 | - `primary_region` (String) Primary region for the database (Only works if region='global'. Can be one of [us-east-1, us-west-1, us-west-2, eu-central-1, eu-west-1, sa-east-1, ap-southeast-1, ap-southeast-2]) 41 | - `prod_pack` (Boolean) Whether Prod Pack is enabled for the database. 42 | - `read_regions` (Set of String) Read regions for the database (Only works if region='global' and primary_region is set. Can be any combination of [us-east-1, us-west-1, us-west-2, eu-central-1, eu-west-1, sa-east-1, ap-southeast-1, ap-southeast-2], excluding the one given as primary.) 43 | - `tls` (Boolean) When enabled, data is encrypted in transit. TLS is enabled by default for newly created databases and cannot be disabled. 44 | 45 | ### Read-Only 46 | 47 | - `creation_time` (Number) Creation time of the database 48 | - `database_id` (String) Unique Database ID for created database 49 | - `database_type` (String) Type of the database 50 | - `db_daily_bandwidth_limit` (Number) Daily bandwidth limit for the database 51 | - `db_disk_threshold` (Number) Disk threshold for the database 52 | - `db_max_clients` (Number) Max clients for the database 53 | - `db_max_commands_per_second` (Number) Max commands per second for the database 54 | - `db_max_entry_size` (Number) Max entry size for the database 55 | - `db_max_request_size` (Number) Max request size for the database 56 | - `db_memory_threshold` (Number) Memory threshold for the database 57 | - `endpoint` (String) Database URL for connection 58 | - `id` (String) The ID of this resource. 59 | - `password` (String, Sensitive) Password of the database 60 | - `port` (Number) Port of the endpoint 61 | - `read_only_rest_token` (String, Sensitive) Rest Token for the database. 62 | - `rest_token` (String, Sensitive) Rest Token for the database. 63 | - `state` (String) State of the database 64 | - `user_email` (String) User email for the database 65 | 66 | 67 | -------------------------------------------------------------------------------- /integrationtesting/upstash_vector_index_test.go: -------------------------------------------------------------------------------- 1 | package integrationtesting 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "strconv" 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | var vectorIndexName, vectorIndexType, vectorIndexRegion, vectorIndexSimilarityFunction, vectorIndexDimensionCount string 12 | 13 | func TestUpstashVectorIndexMAIN(t *testing.T) { 14 | envVars := GetEnvVars() 15 | 16 | email = envVars.Email 17 | apikey = envVars.Apikey 18 | vectorIndexName = envVars.VectorIndexName 19 | vectorIndexType = envVars.VectorIndexType 20 | vectorIndexRegion = envVars.VectorIndexRegion 21 | vectorIndexDimensionCount = strconv.Itoa(envVars.VectorIndexDimensionCount) 22 | vectorIndexSimilarityFunction = envVars.VectorIndexSimilarityFunction 23 | 24 | terraformOptions := vectorIndexOptions(t) 25 | 26 | defer terraform.Destroy(t, terraformOptions) 27 | 28 | terraform.Apply(t, terraformOptions) 29 | terraform.Plan(t, terraformOptions) 30 | vectorIndexAsserter(t, terraformOptions) 31 | 32 | UpstashVectorIndexRecreate(t) 33 | UpstashVectorIndexUpdate(t) 34 | } 35 | 36 | func UpstashVectorIndexRecreate(t *testing.T) { 37 | 38 | vectorIndexName = vectorIndexName + "Updated" 39 | vectorIndexType = "fixed" 40 | 41 | terraformOptions := vectorIndexOptions(t) 42 | terraform.Apply(t, terraformOptions) 43 | terraform.Plan(t, terraformOptions) 44 | vectorIndexAsserter(t, terraformOptions) 45 | } 46 | 47 | func UpstashVectorIndexUpdate(t *testing.T) { 48 | 49 | vectorIndexDimensionCount = "512" 50 | vectorIndexSimilarityFunction = "COSINE" 51 | 52 | terraformOptions := vectorIndexOptions(t) 53 | terraform.Apply(t, terraformOptions) 54 | terraform.Plan(t, terraformOptions) 55 | vectorIndexAsserter(t, terraformOptions) 56 | } 57 | 58 | func vectorIndexAsserter(t *testing.T, terraformOptions *terraform.Options) { 59 | indexNameOutput := terraform.Output(t, terraformOptions, "name") 60 | assert.Equal(t, vectorIndexName, indexNameOutput, "The output name should be the same as the input name") 61 | 62 | indexTypeOutput := terraform.Output(t, terraformOptions, "type") 63 | assert.Equal(t, vectorIndexType, indexTypeOutput, "The output type should be the same as the input type") 64 | 65 | indexRegionOutput := terraform.Output(t, terraformOptions, "region") 66 | assert.Equal(t, vectorIndexRegion, indexRegionOutput, "The output region should be the same as the input region") 67 | 68 | indexDimensionCountOutput := terraform.Output(t, terraformOptions, "dimension_count") 69 | assert.Equal(t, vectorIndexDimensionCount, indexDimensionCountOutput, "The output dimension count should be the same as the input dimension count") 70 | 71 | indexSimilarityFunctionOutput := terraform.Output(t, terraformOptions, "similarity_function") 72 | assert.Equal(t, vectorIndexSimilarityFunction, indexSimilarityFunctionOutput, "The output similarity function should be the same as the input similarity function") 73 | } 74 | 75 | func vectorIndexOptions(t *testing.T) *terraform.Options { 76 | terraformOptions := &terraform.Options{ 77 | TerraformDir: "../examples/examples/vector_index", 78 | Vars: map[string]interface{}{ 79 | "email": email, 80 | "api_key": apikey, 81 | "name": vectorIndexName, 82 | "type": vectorIndexType, 83 | "region": vectorIndexRegion, 84 | "dimension_count": vectorIndexDimensionCount, 85 | "similarity_function": vectorIndexSimilarityFunction, 86 | }, 87 | } 88 | return terraformOptions 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Upstash Terraform Provider 2 | 3 | This is the repository of official [Upstash Terraform provider](https://registry.terraform.io/providers/upstash/upstash/latest). 4 | 5 | ## Installation 6 | 7 | ```hcl 8 | 9 | terraform { 10 | required_providers { 11 | upstash = { 12 | source = "upstash/upstash" 13 | version = "x.x.x" 14 | } 15 | } 16 | } 17 | 18 | provider "upstash" { 19 | email = var.email 20 | api_key = var.api_key 21 | } 22 | ``` 23 | 24 | `email` is your registered email in Upstash. 25 | 26 | `api_key` can be generated from Upstash Console. For more information please check our [docs](https://docs.upstash.com/howto/developerapi). 27 | 28 | ## Create Database Using Terraform 29 | 30 | Here example code snippet that creates database: 31 | 32 | ```hcl 33 | resource "upstash_redis_database" "redis" { 34 | database_name = "db-name" 35 | region = "eu-west-1" 36 | tls = "true" 37 | multi_zone = "false" 38 | } 39 | ``` 40 | ## Import Resources From Outside of Terraform 41 | To import resources created outside of the terraform provider, simply create the resource in .tf file as follows: 42 | ```hcl 43 | resource "upstash_redis_database" "redis" {} 44 | ``` 45 | after this, you can run the command: 46 | ``` 47 | terraform import upstash_redis_database.redis 48 | ``` 49 | 50 | Above example is given for an Upstash Redis database. You can import all of the resources by changing the resource type and providing the resource id. 51 | 52 | You can check full spec and [doc from here](https://registry.terraform.io/providers/upstash/upstash/latest/docs). 53 | 54 | ## Support, Bugs Reports, Feature Requests 55 | 56 | If you need support then you can ask your questions Upstash Team in [upstash.com](https://upstash.com) chat widget. 57 | 58 | There is also discord channel available for community. [Please check here](https://docs.upstash.com/help/support) for more information. 59 | 60 | 61 | ## Requirements 62 | 63 | * Terraform v0.13 and above 64 | * Go 1.16 (to build the provider) 65 | 66 | ## Development 67 | 68 | If you want to locally build/test the provider then follow these steps: 69 | 70 | * Build the provider using: `go build .` command, it will create executable in same directory 71 | * create `terraform.rc` file that contains following configuration. 72 | * export `TF_CLI_CONFIG_FILE` env variable that locates `terraform.rc` file. 73 | * Now your `terraform` commands will use local Upstash provider. 74 | ```hcl 75 | provider_installation { 76 | dev_overrides { 77 | "upstash" = "[PATH THAT CONTAINS CUSTOM PROVIDER]" 78 | } 79 | direct {} 80 | } 81 | ``` 82 | 83 | ### Updating the Docs 84 | This provider uses `tfplugindocs` to generate its documentation. Run the command below, and the docs will be automatically generated from the provider code and examples 85 | ``` 86 | tfplugindocs 87 | ``` 88 | ### Testing 89 | 90 | * First set your environment variables using the `envSetters.txt` file. 91 | 92 | ```shell 93 | source envSetters.txt 94 | ``` 95 | 96 | * Then, navigate to `integrationtesting` folder, and un the tests using the following command: 97 | 98 | ```shell 99 | go test -v 100 | ``` 101 | 102 | If you want to run a specific test, you can use the `-run` flag. To run the test, first navigate to `integrationtesting` folder, and then run the following command. You can replace `TestUpstashVectorIndexMAIN` with the name of the test you want to run. 103 | 104 | ```shell 105 | go test -v . -run TestUpstashVectorIndexMAIN 106 | ``` 107 | -------------------------------------------------------------------------------- /upstash/search/crud.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 7 | 8 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 9 | 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 12 | ) 13 | 14 | func resourceSearchCreate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 15 | c := m.(*client.UpstashClient) 16 | 17 | search, err := CreateSearch(c, CreateSearchRequest{ 18 | Name: data.Get("name").(string), 19 | Region: data.Get("region").(string), 20 | Type: data.Get("type").(string), 21 | }) 22 | if err != nil { 23 | return diag.FromErr(err) 24 | } 25 | 26 | data.SetId(search.Id) 27 | 28 | err = data.Set("id", search.Id) 29 | if err != nil { 30 | return diag.FromErr(err) 31 | } 32 | 33 | return resourceSearchRead(ctx, data, m) 34 | } 35 | 36 | func resourceSearchRead(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 37 | c := m.(*client.UpstashClient) 38 | searchId := data.Get("id").(string) 39 | 40 | if searchId == "" { 41 | searchId = data.Id() 42 | } 43 | 44 | search, err := GetSearch(c, searchId) 45 | if err != nil { 46 | return diag.FromErr(err) 47 | } 48 | 49 | data.SetId(search.Id) 50 | 51 | searchType := search.Type 52 | if searchType == "paid" { 53 | searchType = "payg" 54 | } 55 | 56 | mapping := map[string]interface{}{ 57 | "customer_id": search.CustomerId, 58 | "id": search.Id, 59 | "name": search.Name, 60 | "endpoint": search.Endpoint, 61 | "token": search.Token, 62 | "read_only_token": search.ReadOnlyToken, 63 | "type": searchType, 64 | "region": search.Region, 65 | "max_vector_count": search.MaxVectorCount, 66 | "max_daily_updates": search.MaxDailyUpdates, 67 | "max_daily_queries": search.MaxDailyQueries, 68 | "max_monthly_bandwidth": search.MaxMonthlyBandwidth, 69 | "max_writes_per_second": search.MaxWritesPerSecond, 70 | "max_query_per_second": search.MaxQueryPerSecond, 71 | "max_reads_per_request": search.MaxReadsPerRequest, 72 | "max_writes_per_request": search.MaxWritesPerRequest, 73 | "max_total_metadata_size": search.MaxTotalMetadataSize, 74 | "reserved_price": search.ReservedPrice, 75 | "creation_time": search.CreationTime, 76 | } 77 | 78 | return utils.SetAndCheckErrors(data, mapping) 79 | } 80 | 81 | func resourceSearchUpdate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 82 | c := m.(*client.UpstashClient) 83 | searchId := data.Get("id").(string) 84 | 85 | if data.HasChange("type") { 86 | err := SetSearchPlan(c, searchId, SetPlanRequest{TargetPlan: data.Get("type").(string)}) 87 | if err != nil { 88 | return diag.FromErr(err) 89 | } 90 | } 91 | 92 | if data.HasChange("name") { 93 | err := RenameSearch(c, searchId, RenameSearchRequest{Name: data.Get("name").(string)}) 94 | if err != nil { 95 | return diag.FromErr(err) 96 | } 97 | } 98 | 99 | return resourceSearchRead(ctx, data, m) 100 | } 101 | 102 | func resourceSearchDelete(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 103 | c := m.(*client.UpstashClient) 104 | searchId := data.Get("id").(string) 105 | 106 | err := DeleteSearch(c, searchId) 107 | 108 | if err != nil { 109 | return diag.FromErr(err) 110 | } 111 | 112 | return nil 113 | } 114 | -------------------------------------------------------------------------------- /upstash/vector/index/crud.go: -------------------------------------------------------------------------------- 1 | package index 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 7 | 8 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 9 | 10 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 11 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 12 | ) 13 | 14 | func resourceIndexCreate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 15 | c := m.(*client.UpstashClient) 16 | 17 | index, err := CreateIndex(c, CreateIndexRequest{ 18 | Name: data.Get("name").(string), 19 | SimilarityFunction: data.Get("similarity_function").(string), 20 | DimensionCount: data.Get("dimension_count").(int), 21 | Region: data.Get("region").(string), 22 | Type: data.Get("type").(string), 23 | }) 24 | 25 | if err != nil { 26 | return diag.FromErr(err) 27 | } 28 | 29 | data.SetId(index.Id) 30 | 31 | err = data.Set("id", index.Id) 32 | if err != nil { 33 | return diag.FromErr(err) 34 | } 35 | 36 | return resourceIndexRead(ctx, data, m) 37 | } 38 | 39 | func resourceIndexRead(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 40 | c := m.(*client.UpstashClient) 41 | indexId := data.Get("id").(string) 42 | 43 | if indexId == "" { 44 | indexId = data.Id() 45 | } 46 | 47 | index, err := GetIndex(c, indexId) 48 | if err != nil { 49 | return diag.FromErr(err) 50 | } 51 | data.SetId(index.Id) 52 | 53 | indexType := index.Type 54 | if indexType == "paid" { 55 | indexType = "payg" 56 | } 57 | 58 | mapping := map[string]interface{}{ 59 | "customer_id": index.CustomerId, 60 | "id": index.Id, 61 | "name": index.Name, 62 | "similarity_function": index.SimilarityFunction, 63 | "dimension_count": index.DimensionCount, 64 | "endpoint": index.Endpoint, 65 | "token": index.Token, 66 | "read_only_token": index.ReadOnlyToken, 67 | "type": indexType, 68 | "region": index.Region, 69 | "max_vector_count": index.MaxVectorCount, 70 | "max_daily_updates": index.MaxDailyUpdates, 71 | "max_daily_queries": index.MaxDailyQueries, 72 | "max_monthly_bandwidth": index.MaxMonthlyBandwidth, 73 | "max_writes_per_second": index.MaxWritesPerSecond, 74 | "max_query_per_second": index.MaxQueryPerSecond, 75 | "max_reads_per_request": index.MaxReadsPerRequest, 76 | "max_writes_per_request": index.MaxWritesPerRequest, 77 | "max_total_metadata_size": index.MaxTotalMetadataSize, 78 | "reserved_price": index.ReservedPrice, 79 | "creation_time": index.CreationTime, 80 | } 81 | 82 | return utils.SetAndCheckErrors(data, mapping) 83 | } 84 | 85 | func resourceIndexUpdate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 86 | c := m.(*client.UpstashClient) 87 | indexId := data.Get("id").(string) 88 | 89 | if data.HasChange("type") { 90 | err := SetIndexPlan(c, indexId, SetPlanRequest{TargetPlan: data.Get("type").(string)}) 91 | if err != nil { 92 | return diag.FromErr(err) 93 | } 94 | } 95 | 96 | if data.HasChange("name") { 97 | err := RenameIndex(c, indexId, RenameIndexRequest{Name: data.Get("name").(string)}) 98 | if err != nil { 99 | return diag.FromErr(err) 100 | } 101 | } 102 | 103 | return resourceIndexRead(ctx, data, m) 104 | } 105 | 106 | func resourceIndexDelete(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 107 | c := m.(*client.UpstashClient) 108 | indexId := data.Get("id").(string) 109 | 110 | err := DeleteIndex(c, indexId) 111 | 112 | if err != nil { 113 | return diag.FromErr(err) 114 | } 115 | 116 | return nil 117 | } 118 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Git ### 2 | # Created by git for backups. To disable backups in Git: 3 | # $ git config --global mergetool.keepBackup false 4 | *.orig 5 | 6 | # Created by git when using merge tools for conflicts 7 | *.BACKUP.* 8 | *.BASE.* 9 | *.LOCAL.* 10 | *.REMOTE.* 11 | *_BACKUP_*.txt 12 | *_BASE_*.txt 13 | *_LOCAL_*.txt 14 | *_REMOTE_*.txt 15 | 16 | ### Intellij+all ### 17 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 18 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 19 | 20 | # User-specific stuff 21 | .idea/**/workspace.xml 22 | .idea/**/tasks.xml 23 | .idea/**/usage.statistics.xml 24 | .idea/**/dictionaries 25 | .idea/**/shelf 26 | 27 | # AWS User-specific 28 | .idea/**/aws.xml 29 | 30 | # Generated files 31 | .idea/**/contentModel.xml 32 | 33 | # Sensitive or high-churn files 34 | .idea/**/dataSources/ 35 | .idea/**/dataSources.ids 36 | .idea/**/dataSources.local.xml 37 | .idea/**/sqlDataSources.xml 38 | .idea/**/dynamic.xml 39 | .idea/**/uiDesigner.xml 40 | .idea/**/dbnavigator.xml 41 | 42 | # Gradle 43 | .idea/**/gradle.xml 44 | .idea/**/libraries 45 | 46 | # Gradle and Maven with auto-import 47 | # When using Gradle or Maven with auto-import, you should exclude module files, 48 | # since they will be recreated, and may cause churn. Uncomment if using 49 | # auto-import. 50 | # .idea/artifacts 51 | # .idea/compiler.xml 52 | # .idea/jarRepositories.xml 53 | # .idea/modules.xml 54 | # .idea/*.iml 55 | # .idea/modules 56 | # *.iml 57 | # *.ipr 58 | 59 | # CMake 60 | cmake-build-*/ 61 | 62 | # Mongo Explorer plugin 63 | .idea/**/mongoSettings.xml 64 | 65 | # File-based project format 66 | *.iws 67 | 68 | # IntelliJ 69 | out/ 70 | 71 | # mpeltonen/sbt-idea plugin 72 | .idea_modules/ 73 | 74 | # JIRA plugin 75 | atlassian-ide-plugin.xml 76 | 77 | # Cursive Clojure plugin 78 | .idea/replstate.xml 79 | 80 | # Crashlytics plugin (for Android Studio and IntelliJ) 81 | com_crashlytics_export_strings.xml 82 | crashlytics.properties 83 | crashlytics-build.properties 84 | fabric.properties 85 | 86 | # Editor-based Rest Client 87 | .idea/httpRequests 88 | 89 | # Android studio 3.1+ serialized cache file 90 | .idea/caches/build_file_checksums.ser 91 | 92 | ### Intellij+all Patch ### 93 | # Ignores the whole .idea folder and all .iml files 94 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 95 | 96 | .idea/ 97 | 98 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 99 | 100 | *.iml 101 | modules.xml 102 | .idea/misc.xml 103 | *.ipr 104 | 105 | # Sonarlint plugin 106 | .idea/sonarlint 107 | 108 | ### Terraform ### 109 | # Local .terraform directories 110 | **/.terraform/* 111 | 112 | # .tfstate files 113 | *.tfstate 114 | *.tfstate.* 115 | 116 | # Crash log files 117 | crash.log 118 | 119 | # Exclude all .tfvars files, which are likely to contain sentitive data, such as 120 | # password, private keys, and other secrets. These should not be part of version 121 | # control as they are data points which are potentially sensitive and subject 122 | # to change depending on the environment. 123 | # 124 | *.tfvars 125 | 126 | # Ignore override files as they are usually used to override resources locally and so 127 | # are not checked in 128 | override.tf 129 | override.tf.json 130 | *_override.tf 131 | *_override.tf.json 132 | 133 | # Include override files you do wish to add to version control using negated pattern 134 | # !example_override.tf 135 | 136 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 137 | # example: *tfplan* 138 | 139 | # Ignore CLI configuration files 140 | .terraformrc 141 | terraform.rc 142 | 143 | # End of https://www.toptal.com/developers/gitignore/api/intellij+all,git,terraform 144 | 145 | test/** 146 | terraform-provider-upstash 147 | tfplugindocs 148 | 149 | **.terraform.lock.hcl** 150 | localEnvSetters.txt 151 | -------------------------------------------------------------------------------- /upstash/qstash_v2/topic/crud.go: -------------------------------------------------------------------------------- 1 | package topic 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 8 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 9 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 10 | ) 11 | 12 | func resourceTopicRead(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 13 | c := m.(*client.UpstashClient) 14 | topicName := data.Get("name").(string) 15 | 16 | if topicName == "" { 17 | topicName = data.Id() 18 | } 19 | 20 | topic, err := getTopic(c, topicName) 21 | if err != nil { 22 | return diag.FromErr(err) 23 | } 24 | 25 | data.SetId("upstash-qstash-topic-" + topic.Name) 26 | 27 | var endpointMap []string 28 | for _, val := range topic.Endpoints { 29 | endpointMap = append(endpointMap, val.Url) 30 | } 31 | 32 | mapping := map[string]interface{}{ 33 | "name": topic.Name, 34 | "created_at": topic.UpdatedAt, 35 | "updated_at": topic.UpdatedAt, 36 | "endpoints": endpointMap, 37 | } 38 | 39 | return utils.SetAndCheckErrors(data, mapping) 40 | } 41 | 42 | func resourceTopicCreate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 43 | c := m.(*client.UpstashClient) 44 | topicName := data.Get("name").(string) 45 | 46 | var endpoints []QStashEndpoint 47 | for _, v := range (data.Get("endpoints").(*schema.Set)).List() { 48 | if v != nil { 49 | endpoints = append(endpoints, QStashEndpoint{Url: v.(string)}) 50 | } 51 | } 52 | 53 | err := createTopic(c, topicName, UpdateQStashTopicEndpoints{Endpoints: endpoints}) 54 | if err != nil { 55 | return diag.FromErr(err) 56 | } 57 | 58 | data.SetId("upstash-qstash-topic-" + topicName) 59 | data.Set("name", topicName) 60 | return resourceTopicRead(ctx, data, m) 61 | } 62 | 63 | func resourceTopicDelete(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 64 | c := m.(*client.UpstashClient) 65 | topicName := data.Get("name").(string) 66 | err := deleteTopic(c, topicName) 67 | if err != nil { 68 | return diag.FromErr(err) 69 | } 70 | return nil 71 | } 72 | 73 | func resourceTopicUpdate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 74 | c := m.(*client.UpstashClient) 75 | topicName := data.Get("name").(string) 76 | 77 | if data.HasChange("endpoints") { 78 | a, b := data.GetChange("endpoints") 79 | old := a.(*schema.Set).List() 80 | new := b.(*schema.Set).List() 81 | 82 | var endpointsToRemove []QStashEndpoint 83 | var endpointsToAdd []QStashEndpoint 84 | 85 | if len(new) == 0 { 86 | return diag.Errorf("At least 1 Url is required for a topic.") 87 | } 88 | 89 | for _, oldEndpoint := range old { 90 | needsRemoval := true 91 | for _, newEndpoint := range new { 92 | if newEndpoint.(string) == oldEndpoint.(string) { 93 | needsRemoval = false 94 | break 95 | } 96 | } 97 | if needsRemoval { 98 | endpointsToRemove = append(endpointsToRemove, QStashEndpoint{Url: oldEndpoint.(string)}) 99 | } 100 | } 101 | 102 | for _, newEndpoint := range new { 103 | needsAdding := true 104 | for _, oldEndpoint := range old { 105 | if newEndpoint.(string) == oldEndpoint.(string) { 106 | needsAdding = false 107 | break 108 | } 109 | } 110 | if needsAdding { 111 | endpointsToAdd = append(endpointsToAdd, QStashEndpoint{Url: newEndpoint.(string)}) 112 | } 113 | } 114 | 115 | if len(endpointsToAdd) > 0 { 116 | if err := addEndpointsToTopic(c, topicName, UpdateQStashTopicEndpoints{Endpoints: endpointsToAdd}); err != nil { 117 | return diag.FromErr((err)) 118 | } 119 | } 120 | 121 | if len(endpointsToRemove) > 0 { 122 | if err := deleteEndpointsFromTopic(c, topicName, UpdateQStashTopicEndpoints{Endpoints: endpointsToRemove}); err != nil { 123 | return diag.FromErr((err)) 124 | } 125 | } 126 | 127 | } 128 | 129 | return resourceTopicRead(ctx, data, m) 130 | } 131 | -------------------------------------------------------------------------------- /upstash/search/data_source.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func DataResourceSearch() *schema.Resource { 8 | return &schema.Resource{ 9 | ReadContext: resourceSearchRead, 10 | 11 | Schema: map[string]*schema.Schema{ 12 | "customer_id": { 13 | Type: schema.TypeString, 14 | Computed: true, 15 | Description: "The unique ID associated to the owner of this search.", 16 | }, 17 | "id": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | Description: "Unique Search ID for created search.", 21 | }, 22 | "name": { 23 | Type: schema.TypeString, 24 | Computed: true, 25 | Description: "Name of the search.", 26 | }, 27 | "endpoint": { 28 | Type: schema.TypeString, 29 | Computed: true, 30 | Description: "Associated endpoint of your search.", 31 | }, 32 | "token": { 33 | Type: schema.TypeString, 34 | Computed: true, 35 | Sensitive: true, 36 | Description: "REST token to send request to the related search.", 37 | }, 38 | "read_only_token": { 39 | Type: schema.TypeString, 40 | Computed: true, 41 | Sensitive: true, 42 | Description: "Readonly REST token to send request to the related search. You can't perform update operation with this token.", 43 | }, 44 | "type": { 45 | Type: schema.TypeString, 46 | Computed: true, 47 | Description: "Associated plan of the search.", 48 | }, 49 | "region": { 50 | Type: schema.TypeString, 51 | Computed: true, 52 | Description: "The region where your search is deployed.", 53 | }, 54 | "max_vector_count": { 55 | Type: schema.TypeInt, 56 | Computed: true, 57 | Description: "The number of maximum that your search can contain.", 58 | }, 59 | "max_daily_updates": { 60 | Type: schema.TypeInt, 61 | Computed: true, 62 | Description: "The number of maximum update operations you can perform in a day. Only upsert operations are included in update count.", 63 | }, 64 | "max_daily_queries": { 65 | Type: schema.TypeInt, 66 | Computed: true, 67 | Description: "The number of maximum query operations you can perform in a day. Only query operations are included in query count.", 68 | }, 69 | "max_monthly_bandwidth": { 70 | Type: schema.TypeInt, 71 | Computed: true, 72 | Description: "The maximum amount of monthly bandwidth for the search. Unit is bytes. `-1` if the limit is unlimited.", 73 | }, 74 | "max_writes_per_second": { 75 | Type: schema.TypeInt, 76 | Computed: true, 77 | Description: "The number of maximum write operations you can perform per second. Only upsert operations are included in write count.", 78 | }, 79 | "max_query_per_second": { 80 | Type: schema.TypeInt, 81 | Computed: true, 82 | Description: "The number of maximum query operations you can perform per second. Only query operations are included in query count.", 83 | }, 84 | "max_reads_per_request": { 85 | Type: schema.TypeInt, 86 | Computed: true, 87 | Description: "The number of maximum vectors in a read operation. Query and fetch operations are included in read operations.", 88 | }, 89 | "max_writes_per_request": { 90 | Type: schema.TypeInt, 91 | Computed: true, 92 | Description: "The number of maximum vectors in a write operation. Only upsert operations are included in write operations.", 93 | }, 94 | "max_total_metadata_size": { 95 | Type: schema.TypeInt, 96 | Computed: true, 97 | Description: "The amount of maximum size for the total metadata sizes in your search.", 98 | }, 99 | "reserved_price": { 100 | Type: schema.TypeFloat, 101 | Computed: true, 102 | Description: "Monthly pricing of your search. Only available for fixed and pro plans.", 103 | }, 104 | "creation_time": { 105 | Type: schema.TypeInt, 106 | Computed: true, 107 | Description: "The creation time of the search in UTC as unix timestamp.", 108 | }, 109 | }, 110 | Importer: &schema.ResourceImporter{ 111 | StateContext: schema.ImportStatePassthroughContext, 112 | }, 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /upstash/search/resource.go: -------------------------------------------------------------------------------- 1 | package search 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func ResourceSearch() *schema.Resource { 8 | return &schema.Resource{ 9 | CreateContext: resourceSearchCreate, 10 | ReadContext: resourceSearchRead, 11 | UpdateContext: resourceSearchUpdate, 12 | DeleteContext: resourceSearchDelete, 13 | Schema: map[string]*schema.Schema{ 14 | "customer_id": { 15 | Type: schema.TypeString, 16 | Computed: true, 17 | Description: "The unique ID associated to the owner of this search.", 18 | }, 19 | "id": { 20 | Type: schema.TypeString, 21 | Computed: true, 22 | Description: "Unique Search ID for created search.", 23 | }, 24 | "name": { 25 | Type: schema.TypeString, 26 | Required: true, 27 | Description: "Name of the search.", 28 | }, 29 | "endpoint": { 30 | Type: schema.TypeString, 31 | Computed: true, 32 | Description: "Associated endpoint of your search.", 33 | }, 34 | "token": { 35 | Type: schema.TypeString, 36 | Computed: true, 37 | Sensitive: true, 38 | Description: "REST token to send request to the related search.", 39 | }, 40 | "read_only_token": { 41 | Type: schema.TypeString, 42 | Computed: true, 43 | Sensitive: true, 44 | Description: "Readonly REST token to send request to the related search. You can't perform update operation with this token.", 45 | }, 46 | "type": { 47 | Type: schema.TypeString, 48 | Required: true, 49 | Description: "Associated plan of the search. `payg` can be used", 50 | }, 51 | "region": { 52 | Type: schema.TypeString, 53 | Required: true, 54 | Description: "The region where your search is deployed.", 55 | }, 56 | "max_vector_count": { 57 | Type: schema.TypeInt, 58 | Computed: true, 59 | Description: "The number of maximum that your search can contain.", 60 | }, 61 | "max_daily_updates": { 62 | Type: schema.TypeInt, 63 | Computed: true, 64 | Description: "The number of maximum update operations you can perform in a day. Only upsert operations are included in update count.", 65 | }, 66 | "max_daily_queries": { 67 | Type: schema.TypeInt, 68 | Computed: true, 69 | Description: "The number of maximum query operations you can perform in a day. Only query operations are included in query count.", 70 | }, 71 | "max_monthly_bandwidth": { 72 | Type: schema.TypeInt, 73 | Computed: true, 74 | Description: "The maximum amount of monthly bandwidth for the search. Unit is bytes. `-1` if the limit is unlimited.", 75 | }, 76 | "max_writes_per_second": { 77 | Type: schema.TypeInt, 78 | Computed: true, 79 | Description: "The number of maximum write operations you can perform per second. Only upsert operations are included in write count.", 80 | }, 81 | "max_query_per_second": { 82 | Type: schema.TypeInt, 83 | Computed: true, 84 | Description: "The number of maximum query operations you can perform per second. Only query operations are included in query count.", 85 | }, 86 | "max_reads_per_request": { 87 | Type: schema.TypeInt, 88 | Computed: true, 89 | Description: "The number of maximum vectors in a read operation. Query and fetch operations are included in read operations.", 90 | }, 91 | "max_writes_per_request": { 92 | Type: schema.TypeInt, 93 | Computed: true, 94 | Description: "The number of maximum vectors in a write operation. Only upsert operations are included in write operations.", 95 | }, 96 | "max_total_metadata_size": { 97 | Type: schema.TypeInt, 98 | Computed: true, 99 | Description: "The amount of maximum size for the total metadata sizes in your search.", 100 | }, 101 | "reserved_price": { 102 | Type: schema.TypeFloat, 103 | Computed: true, 104 | Optional: true, 105 | Description: "Monthly pricing of your search. Only available for fixed and pro plans.", 106 | }, 107 | "creation_time": { 108 | Type: schema.TypeInt, 109 | Computed: true, 110 | Description: "The creation time of the search in UTC as unix timestamp.", 111 | }, 112 | }, 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /upstash/vector/index/data_source.go: -------------------------------------------------------------------------------- 1 | package index 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func DataResourceIndex() *schema.Resource { 8 | return &schema.Resource{ 9 | ReadContext: resourceIndexRead, 10 | 11 | Schema: map[string]*schema.Schema{ 12 | "customer_id": { 13 | Type: schema.TypeString, 14 | Computed: true, 15 | Description: "The unique ID associated to the owner of this index.", 16 | }, 17 | "id": { 18 | Type: schema.TypeString, 19 | Required: true, 20 | Description: "Unique Index ID for created index.", 21 | }, 22 | "name": { 23 | Type: schema.TypeString, 24 | Computed: true, 25 | Description: "Name of the index.", 26 | }, 27 | "similarity_function": { 28 | Type: schema.TypeString, 29 | Computed: true, 30 | Description: "Associated distance metric to calculate the similarity.", 31 | }, 32 | "dimension_count": { 33 | Type: schema.TypeInt, 34 | Computed: true, 35 | Description: "Size of the vector array.", 36 | }, 37 | "endpoint": { 38 | Type: schema.TypeString, 39 | Computed: true, 40 | Description: "Associated endpoint of your index.", 41 | }, 42 | "token": { 43 | Type: schema.TypeString, 44 | Computed: true, 45 | Sensitive: true, 46 | Description: "REST token to send request to the related index.", 47 | }, 48 | "read_only_token": { 49 | Type: schema.TypeString, 50 | Computed: true, 51 | Sensitive: true, 52 | Description: "Readonly REST token to send request to the related index. You can't perform update operation with this token.", 53 | }, 54 | "type": { 55 | Type: schema.TypeString, 56 | Computed: true, 57 | Description: "Associated plan of the index. Either `free`, `paid`, `fixed` or `pro`.", 58 | }, 59 | "region": { 60 | Type: schema.TypeString, 61 | Computed: true, 62 | Description: "The region where your index is deployed.", 63 | }, 64 | "max_vector_count": { 65 | Type: schema.TypeInt, 66 | Computed: true, 67 | Description: "The number of maximum that your index can contain.", 68 | }, 69 | "max_daily_updates": { 70 | Type: schema.TypeInt, 71 | Computed: true, 72 | Description: "The number of maximum update operations you can perform in a day. Only upsert operations are included in update count.", 73 | }, 74 | "max_daily_queries": { 75 | Type: schema.TypeInt, 76 | Computed: true, 77 | Description: "The number of maximum query operations you can perform in a day. Only query operations are included in query count.", 78 | }, 79 | "max_monthly_bandwidth": { 80 | Type: schema.TypeInt, 81 | Computed: true, 82 | Description: "The maximum amount of monthly bandwidth for the index. Unit is bytes. `-1` if the limit is unlimited.", 83 | }, 84 | "max_writes_per_second": { 85 | Type: schema.TypeInt, 86 | Computed: true, 87 | Description: "The number of maximum write operations you can perform per second. Only upsert operations are included in write count.", 88 | }, 89 | "max_query_per_second": { 90 | Type: schema.TypeInt, 91 | Computed: true, 92 | Description: "The number of maximum query operations you can perform per second. Only query operations are included in query count.", 93 | }, 94 | "max_reads_per_request": { 95 | Type: schema.TypeInt, 96 | Computed: true, 97 | Description: "The number of maximum vectors in a read operation. Query and fetch operations are included in read operations.", 98 | }, 99 | "max_writes_per_request": { 100 | Type: schema.TypeInt, 101 | Computed: true, 102 | Description: "The number of maximum vectors in a write operation. Only upsert operations are included in write operations.", 103 | }, 104 | "max_total_metadata_size": { 105 | Type: schema.TypeInt, 106 | Computed: true, 107 | Description: "The amount of maximum size for the total metadata sizes in your index.", 108 | }, 109 | "reserved_price": { 110 | Type: schema.TypeFloat, 111 | Computed: true, 112 | Description: "Monthly pricing of your index. Only available for fixed and pro plans.", 113 | }, 114 | "creation_time": { 115 | Type: schema.TypeInt, 116 | Computed: true, 117 | Description: "The creation time of the vector index in UTC as unix timestamp.", 118 | }, 119 | }, 120 | Importer: &schema.ResourceImporter{ 121 | StateContext: schema.ImportStatePassthroughContext, 122 | }, 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /upstash/vector/index/resource.go: -------------------------------------------------------------------------------- 1 | package index 2 | 3 | import ( 4 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 5 | ) 6 | 7 | func ResourceIndex() *schema.Resource { 8 | return &schema.Resource{ 9 | CreateContext: resourceIndexCreate, 10 | ReadContext: resourceIndexRead, 11 | UpdateContext: resourceIndexUpdate, 12 | DeleteContext: resourceIndexDelete, 13 | Schema: map[string]*schema.Schema{ 14 | "customer_id": { 15 | Type: schema.TypeString, 16 | Computed: true, 17 | Description: "The unique ID associated to the owner of this index.", 18 | }, 19 | "id": { 20 | Type: schema.TypeString, 21 | Computed: true, 22 | Description: "Unique Index ID for created index.", 23 | }, 24 | "name": { 25 | Type: schema.TypeString, 26 | Required: true, 27 | Description: "Name of the index.", 28 | }, 29 | "similarity_function": { 30 | Type: schema.TypeString, 31 | Required: true, 32 | Description: "Associated distance metric to calculate the similarity.", 33 | }, 34 | "dimension_count": { 35 | Type: schema.TypeInt, 36 | Required: true, 37 | Description: "Size of the vector array.", 38 | }, 39 | "endpoint": { 40 | Type: schema.TypeString, 41 | Computed: true, 42 | Description: "Associated endpoint of your index.", 43 | }, 44 | "token": { 45 | Type: schema.TypeString, 46 | Computed: true, 47 | Sensitive: true, 48 | Description: "REST token to send request to the related index.", 49 | }, 50 | "read_only_token": { 51 | Type: schema.TypeString, 52 | Computed: true, 53 | Sensitive: true, 54 | Description: "Readonly REST token to send request to the related index. You can't perform update operation with this token.", 55 | }, 56 | "type": { 57 | Type: schema.TypeString, 58 | Required: true, 59 | Description: "Associated plan of the index. Either `free`, `paid`, `fixed` or `pro`.", 60 | }, 61 | "region": { 62 | Type: schema.TypeString, 63 | Required: true, 64 | Description: "The region where your index is deployed.", 65 | }, 66 | "max_vector_count": { 67 | Type: schema.TypeInt, 68 | Computed: true, 69 | Description: "The number of maximum that your index can contain.", 70 | }, 71 | "max_daily_updates": { 72 | Type: schema.TypeInt, 73 | Computed: true, 74 | Description: "The number of maximum update operations you can perform in a day. Only upsert operations are included in update count.", 75 | }, 76 | "max_daily_queries": { 77 | Type: schema.TypeInt, 78 | Computed: true, 79 | Description: "The number of maximum query operations you can perform in a day. Only query operations are included in query count.", 80 | }, 81 | "max_monthly_bandwidth": { 82 | Type: schema.TypeInt, 83 | Computed: true, 84 | Description: "The maximum amount of monthly bandwidth for the index. Unit is bytes. `-1` if the limit is unlimited.", 85 | }, 86 | "max_writes_per_second": { 87 | Type: schema.TypeInt, 88 | Computed: true, 89 | Description: "The number of maximum write operations you can perform per second. Only upsert operations are included in write count.", 90 | }, 91 | "max_query_per_second": { 92 | Type: schema.TypeInt, 93 | Computed: true, 94 | Description: "The number of maximum query operations you can perform per second. Only query operations are included in query count.", 95 | }, 96 | "max_reads_per_request": { 97 | Type: schema.TypeInt, 98 | Computed: true, 99 | Description: "The number of maximum vectors in a read operation. Query and fetch operations are included in read operations.", 100 | }, 101 | "max_writes_per_request": { 102 | Type: schema.TypeInt, 103 | Computed: true, 104 | Description: "The number of maximum vectors in a write operation. Only upsert operations are included in write operations.", 105 | }, 106 | "max_total_metadata_size": { 107 | Type: schema.TypeInt, 108 | Computed: true, 109 | Description: "The amount of maximum size for the total metadata sizes in your index.", 110 | }, 111 | "reserved_price": { 112 | Type: schema.TypeFloat, 113 | Computed: true, 114 | Optional: true, 115 | Description: "Monthly pricing of your index. Only available for fixed and pro plans.", 116 | }, 117 | "creation_time": { 118 | Type: schema.TypeInt, 119 | Computed: true, 120 | Description: "The creation time of the vector index in UTC as unix timestamp.", 121 | }, 122 | }, 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /upstash/redis/database/data_source.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 4 | 5 | func DataSourceDatabase() *schema.Resource { 6 | return &schema.Resource{ 7 | ReadContext: resourceDatabaseRead, 8 | Schema: map[string]*schema.Schema{ 9 | "database_id": { 10 | Type: schema.TypeString, 11 | Required: true, 12 | Description: "Unique Database ID for requested database", 13 | }, 14 | "database_name": { 15 | Type: schema.TypeString, 16 | Computed: true, 17 | Description: "Name of the database", 18 | }, 19 | "region": { 20 | Type: schema.TypeString, 21 | Computed: true, 22 | Description: "Region of the database. For globals, check for primary_region and read_regions fields", 23 | }, 24 | "endpoint": { 25 | Type: schema.TypeString, 26 | Computed: true, 27 | Description: "Database URL for connection", 28 | }, 29 | "password": { 30 | Type: schema.TypeString, 31 | Computed: true, 32 | Sensitive: true, 33 | Description: "Password of the database", 34 | }, 35 | "consistent": { 36 | Type: schema.TypeBool, 37 | Computed: true, 38 | Description: "When enabled database runs in Consistency Mode", 39 | Deprecated: "Consistent option is deprecated.", 40 | }, 41 | "multizone": { 42 | Type: schema.TypeBool, 43 | Computed: true, 44 | Description: "When enabled database is highly available and deployed multi-zone", 45 | Deprecated: "Multizone option is deprecated. It is enabled by default for paid databases.", 46 | }, 47 | "tls": { 48 | Type: schema.TypeBool, 49 | Computed: true, 50 | Description: "When enabled, data is encrypted in transit.", 51 | Deprecated: "TLS option is deprecated. It's enabled by default for all databases.", 52 | }, 53 | "eviction": { 54 | Type: schema.TypeBool, 55 | Computed: true, 56 | Description: "Enable eviction, to evict keys when your database reaches the max size", 57 | }, 58 | "auto_scale": { 59 | Type: schema.TypeBool, 60 | Computed: true, 61 | Description: "Upgrade to higher plans automatically when it hits quotas", 62 | }, 63 | "budget": { 64 | Type: schema.TypeInt, 65 | Computed: true, 66 | Description: "Budget for the database. It is used to limit the cost of the database. If the budget is reached, the database will be throttled until the next month.", 67 | }, 68 | "prod_pack": { 69 | Type: schema.TypeBool, 70 | Computed: true, 71 | Description: "Whether Prod Pack is enabled for the database.", 72 | }, 73 | "primary_region": { 74 | Type: schema.TypeString, 75 | Computed: true, 76 | Description: "Primary region for the database", 77 | }, 78 | "read_regions": { 79 | Type: schema.TypeSet, 80 | Elem: &schema.Schema{ 81 | Type: schema.TypeString, 82 | }, 83 | Computed: true, 84 | Description: "Read regions for the database", 85 | }, 86 | "ip_allowlist": { 87 | Type: schema.TypeSet, 88 | Elem: &schema.Schema{ 89 | Type: schema.TypeString, 90 | }, 91 | Computed: true, 92 | Description: "Ip CIDR allowlist for the database. If not set, all IPs are allowed to connect to the database.", 93 | }, 94 | "port": { 95 | Type: schema.TypeInt, 96 | Computed: true, 97 | Description: "Port of the endpoint", 98 | }, 99 | "rest_token": { 100 | Type: schema.TypeString, 101 | Computed: true, 102 | Sensitive: true, 103 | Description: "Rest Token for the database.", 104 | }, 105 | "read_only_rest_token": { 106 | Type: schema.TypeString, 107 | Computed: true, 108 | Sensitive: true, 109 | Description: "Rest Token for the database.", 110 | }, 111 | "creation_time": { 112 | Type: schema.TypeInt, 113 | Computed: true, 114 | Description: "Creation time of the database", 115 | }, 116 | "database_type": { 117 | Type: schema.TypeString, 118 | Computed: true, 119 | Description: "Type of the database", 120 | }, 121 | "state": { 122 | Type: schema.TypeString, 123 | Computed: true, 124 | Description: "State of the database", 125 | }, 126 | "user_email": { 127 | Type: schema.TypeString, 128 | Computed: true, 129 | Description: "User email for the database", 130 | }, 131 | "db_max_clients": { 132 | Type: schema.TypeInt, 133 | Computed: true, 134 | Description: "Max clients for the database", 135 | }, 136 | "db_max_request_size": { 137 | Type: schema.TypeInt, 138 | Computed: true, 139 | Description: "Max request size for the database", 140 | }, 141 | "db_disk_threshold": { 142 | Type: schema.TypeInt, 143 | Computed: true, 144 | Description: "Disk threshold for the database", 145 | }, 146 | "db_max_entry_size": { 147 | Type: schema.TypeInt, 148 | Computed: true, 149 | Description: "Max entry size for the database", 150 | }, 151 | "db_memory_threshold": { 152 | Type: schema.TypeInt, 153 | Computed: true, 154 | Description: "Memory threshold for the database", 155 | }, 156 | "db_daily_bandwidth_limit": { 157 | Type: schema.TypeInt, 158 | Computed: true, 159 | Description: "Daily bandwidth limit for the database", 160 | }, 161 | "db_max_commands_per_second": { 162 | Type: schema.TypeInt, 163 | Computed: true, 164 | Description: "Max commands per second for the database", 165 | }, 166 | }, 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /upstash/client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "errors" 5 | "net/http" 6 | "strconv" 7 | 8 | "github.com/imroc/req" 9 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 10 | ) 11 | 12 | const UPSTASH_API_ENDPOINT = "https://api.upstash.com" 13 | 14 | type UpstashClient struct { 15 | Email string 16 | Apikey string 17 | } 18 | 19 | func NewUpstashClient(email string, apikey string) *UpstashClient { 20 | return &UpstashClient{ 21 | Email: email, 22 | Apikey: apikey, 23 | } 24 | } 25 | 26 | func (c *UpstashClient) GetQstashEndpoint() string { 27 | return "https://qstash.upstash.io/v1" 28 | } 29 | 30 | func (c *UpstashClient) GetQstashEndpointV2() string { 31 | return "https://qstash.upstash.io/v2" 32 | } 33 | 34 | func (c *UpstashClient) GetQstashToken() (error, string) { 35 | type token struct { 36 | Token string `json:"token"` 37 | } 38 | resp, err := req.Get( 39 | UPSTASH_API_ENDPOINT+"/v2/qstash/user", 40 | req.Header{"Accept": "application/json"}, 41 | req.Header{"Authorization": utils.BasicAuth(c.Email, c.Apikey)}, 42 | ) 43 | if err != nil { 44 | return err, "" 45 | } 46 | var qstashToken token 47 | err = resp.ToJSON(&qstashToken) 48 | 49 | return err, qstashToken.Token 50 | } 51 | 52 | func (c *UpstashClient) SendDeleteRequest(endpointExtensionOrQstashEndpoint string, body interface{}, errMessage string, qstashFlag bool) (err error) { 53 | endpoint := UPSTASH_API_ENDPOINT + endpointExtensionOrQstashEndpoint 54 | authHeader := req.Header{"Authorization": utils.BasicAuth(c.Email, c.Apikey)} 55 | 56 | if qstashFlag { 57 | endpoint = endpointExtensionOrQstashEndpoint 58 | err, authorizationToken := c.GetQstashToken() 59 | if err != nil { 60 | return err 61 | } 62 | authHeader = req.Header{"Authorization": "Bearer " + authorizationToken} 63 | } 64 | 65 | resp, err := req.Delete( 66 | endpoint, 67 | req.Header{"Accept": "application/json"}, 68 | authHeader, 69 | req.BodyJSON(body), 70 | ) 71 | if err != nil { 72 | return err 73 | } 74 | if resp.Response().StatusCode != http.StatusOK && resp.Response().StatusCode != http.StatusAccepted && resp.Response().StatusCode != http.StatusCreated { 75 | return errors.New(errMessage + " failed, status code: " + strconv.Itoa(resp.Response().StatusCode) + " response: " + resp.String()) 76 | } 77 | return err 78 | } 79 | 80 | func (c *UpstashClient) SendGetRequest(endpointExtensionOrQstashEndpoint string, errMessage string, qstashFlag bool) (response *req.Resp, err error) { 81 | endpoint := UPSTASH_API_ENDPOINT + endpointExtensionOrQstashEndpoint 82 | authHeader := req.Header{"Authorization": utils.BasicAuth(c.Email, c.Apikey)} 83 | 84 | if qstashFlag { 85 | endpoint = endpointExtensionOrQstashEndpoint 86 | err, authorizationToken := c.GetQstashToken() 87 | if err != nil { 88 | return response, err 89 | } 90 | authHeader = req.Header{"Authorization": "Bearer " + authorizationToken} 91 | } 92 | 93 | resp, err := req.Get( 94 | endpoint, 95 | req.Header{"Accept": "application/json"}, 96 | authHeader, 97 | ) 98 | if err != nil { 99 | return resp, err 100 | } 101 | if resp.Response().StatusCode != http.StatusOK && resp.Response().StatusCode != http.StatusAccepted && resp.Response().StatusCode != http.StatusCreated { 102 | return resp, errors.New(errMessage + " failed, status code: " + strconv.Itoa(resp.Response().StatusCode) + " response: " + resp.String()) 103 | } 104 | return resp, err 105 | } 106 | 107 | func (c *UpstashClient) SendPostRequest(endpointExtensionOrQstashEndpoint string, body interface{}, errMessage string, qstashFlag bool) (response *req.Resp, err error) { 108 | endpoint := UPSTASH_API_ENDPOINT + endpointExtensionOrQstashEndpoint 109 | authHeader := req.Header{"Authorization": utils.BasicAuth(c.Email, c.Apikey)} 110 | 111 | if qstashFlag { 112 | endpoint = endpointExtensionOrQstashEndpoint 113 | err, authorizationToken := c.GetQstashToken() 114 | if err != nil { 115 | return response, err 116 | } 117 | authHeader = req.Header{"Authorization": "Bearer " + authorizationToken} 118 | } 119 | 120 | resp, err := req.Post( 121 | endpoint, 122 | req.Header{"Accept": "application/json"}, 123 | authHeader, 124 | req.BodyJSON(body), 125 | ) 126 | 127 | if err != nil { 128 | return nil, err 129 | } 130 | if resp.Response().StatusCode != http.StatusOK && resp.Response().StatusCode != http.StatusAccepted && resp.Response().StatusCode != http.StatusCreated { 131 | return nil, errors.New(errMessage + " failed, status code: " + strconv.Itoa(resp.Response().StatusCode) + " response: " + resp.String()) 132 | } 133 | return resp, err 134 | } 135 | 136 | func (c *UpstashClient) SendPutRequest(endpointExtensionOrQstashEndpoint string, body interface{}, errMessage string, qstashFlag bool) (response *req.Resp, err error) { 137 | endpoint := UPSTASH_API_ENDPOINT + endpointExtensionOrQstashEndpoint 138 | authHeader := req.Header{"Authorization": utils.BasicAuth(c.Email, c.Apikey)} 139 | 140 | if qstashFlag { 141 | endpoint = endpointExtensionOrQstashEndpoint 142 | err, authorizationToken := c.GetQstashToken() 143 | if err != nil { 144 | return response, err 145 | } 146 | authHeader = req.Header{"Authorization": "Bearer " + authorizationToken} 147 | } 148 | 149 | resp, err := req.Put( 150 | endpoint, 151 | req.Header{"Accept": "application/json"}, 152 | authHeader, 153 | req.BodyJSON(body), 154 | ) 155 | 156 | if err != nil { 157 | return nil, err 158 | } 159 | if resp.Response().StatusCode != http.StatusOK && resp.Response().StatusCode != http.StatusAccepted && resp.Response().StatusCode != http.StatusCreated { 160 | return nil, errors.New(errMessage + " failed, status code: " + strconv.Itoa(resp.Response().StatusCode) + " response: " + resp.String()) 161 | } 162 | return resp, err 163 | } 164 | 165 | func (c *UpstashClient) SendPatchRequest(endpointExtensionOrQstashEndpoint string, body interface{}, errMessage string, qstashFlag bool) (response *req.Resp, err error) { 166 | endpoint := UPSTASH_API_ENDPOINT + endpointExtensionOrQstashEndpoint 167 | authHeader := req.Header{"Authorization": utils.BasicAuth(c.Email, c.Apikey)} 168 | 169 | if qstashFlag { 170 | endpoint = endpointExtensionOrQstashEndpoint 171 | err, authorizationToken := c.GetQstashToken() 172 | if err != nil { 173 | return response, err 174 | } 175 | authHeader = req.Header{"Authorization": "Bearer " + authorizationToken} 176 | } 177 | 178 | resp, err := req.Patch( 179 | endpoint, 180 | req.Header{"Accept": "application/json"}, 181 | authHeader, 182 | req.BodyJSON(body), 183 | ) 184 | 185 | if err != nil { 186 | return nil, err 187 | } 188 | if resp.Response().StatusCode != http.StatusOK && resp.Response().StatusCode != http.StatusAccepted && resp.Response().StatusCode != http.StatusCreated { 189 | return nil, errors.New(errMessage + " failed, status code: " + strconv.Itoa(resp.Response().StatusCode) + " response: " + resp.String()) 190 | } 191 | return resp, err 192 | } 193 | -------------------------------------------------------------------------------- /upstash/redis/database/crud.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "github.com/hashicorp/terraform-plugin-sdk/v2/diag" 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | "github.com/upstash/terraform-provider-upstash/v2/upstash/client" 10 | "github.com/upstash/terraform-provider-upstash/v2/upstash/utils" 11 | ) 12 | 13 | func resourceDatabaseUpdate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 14 | c := m.(*client.UpstashClient) 15 | databaseId := data.Get("database_id").(string) 16 | 17 | if data.HasChange("read_regions") { 18 | var readRegions []string 19 | primaryRegion := data.Get("primary_region").(string) 20 | 21 | for _, v := range (data.Get("read_regions").(*schema.Set)).List() { 22 | if v.(string) == primaryRegion { 23 | return diag.Errorf(fmt.Sprintf("Primary region '%s' can not be in the list of read regions.", primaryRegion)) 24 | } 25 | readRegions = append([]string{v.(string)}, readRegions...) 26 | } 27 | if err := UpdateReadRegions(c, databaseId, UpdateReadRegionsRequest{readRegions}); err != nil { 28 | return diag.FromErr((err)) 29 | } 30 | } 31 | 32 | if data.HasChange("tls") { 33 | if err := EnableTLS(c, databaseId); err != nil { 34 | return diag.FromErr(err) 35 | } 36 | } 37 | 38 | if data.HasChange("eviction") { 39 | if err := ConfigureEviction(c, databaseId, data.Get("eviction").(bool)); err != nil { 40 | return diag.FromErr(err) 41 | } 42 | } 43 | 44 | if data.HasChange("auto_scale") { 45 | if err := ConfigureAutoUpgrade(c, databaseId, data.Get("auto_scale").(bool)); err != nil { 46 | return diag.FromErr(err) 47 | } 48 | } 49 | 50 | if data.HasChange("prod_pack") { 51 | if err := ConfigureProdPack(c, databaseId, data.Get("prod_pack").(bool)); err != nil { 52 | return diag.FromErr(err) 53 | } 54 | } 55 | 56 | if data.HasChange("budget") { 57 | err := UpdateDBBudget(c, databaseId, UpdateDBBudgetRequest{ 58 | Budget: data.Get("budget").(int), 59 | }) 60 | 61 | if err != nil { 62 | return diag.FromErr(err) 63 | } 64 | } 65 | 66 | if data.HasChange("ip_allowlist") { 67 | var ipAllowList []string 68 | for _, v := range (data.Get("ip_allowlist").(*schema.Set)).List() { 69 | if v != nil { 70 | ipAllowList = append(ipAllowList, v.(string)) 71 | } 72 | } 73 | 74 | err := UpdateDBIpAllowlist(c, databaseId, UpdateDBIpAllowlistRequest{ 75 | AllowedIps: ipAllowList, 76 | }) 77 | 78 | if err != nil { 79 | return diag.FromErr(err) 80 | } 81 | } 82 | 83 | if data.HasChange("consistent") { 84 | if data.Get("consistent").(bool) { 85 | return diag.Errorf("Cannot enable strong consistency on the DB. All the newly created DBs will be eventually consistent. Set consistent=false.") 86 | } 87 | } 88 | 89 | return resourceDatabaseRead(ctx, data, m) 90 | } 91 | 92 | func resourceDatabaseRead(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 93 | c := m.(*client.UpstashClient) 94 | databaseId := data.Get("database_id").(string) 95 | if databaseId == "" { 96 | databaseId = data.Id() 97 | } 98 | database, err := GetDatabase(c, databaseId) 99 | if err != nil { 100 | return diag.FromErr(err) 101 | } 102 | 103 | data.SetId("upstash-database-" + database.DatabaseId) 104 | 105 | mapping := map[string]interface{}{ 106 | "database_id": database.DatabaseId, 107 | "database_name": database.DatabaseName, 108 | "region": database.Region, 109 | "endpoint": database.Endpoint, 110 | "password": database.Password, 111 | "consistent": database.Consistent, 112 | "multizone": database.MultiZone, 113 | "tls": database.Tls, 114 | "eviction": database.Eviction, 115 | "auto_scale": database.AutoUpgrade, 116 | "prod_pack": database.ProdPack, 117 | "budget": database.Budget, 118 | "port": database.Port, 119 | "rest_token": database.RestToken, 120 | "read_only_rest_token": database.ReadOnlyRestToken, 121 | "database_type": database.DatabaseType, 122 | "state": database.State, 123 | "user_email": database.UserEmail, 124 | "db_max_clients": database.DBMaxClients, 125 | "db_max_request_size": database.DBMaxRequestSize, 126 | "db_disk_threshold": database.DBDiskThreshold, 127 | "db_max_entry_size": database.DBMaxEntrySize, 128 | "db_memory_threshold": database.DBMemoryThreshold, 129 | "db_daily_bandwidth_limit": database.DBDailyBandwidthLimit, 130 | "db_max_commands_per_second": database.DBMaxCommandsPerSecond, 131 | "creation_time": database.CreationTime, 132 | "primary_region": database.PrimaryRegion, 133 | } 134 | if len(database.IpAllowList) > 0 { 135 | mapping["ip_allowlist"] = database.IpAllowList 136 | } 137 | 138 | if len(database.ReadRegions) > 0 { 139 | mapping["read_regions"] = database.ReadRegions 140 | } 141 | 142 | return utils.SetAndCheckErrors(data, mapping) 143 | } 144 | 145 | func resourceDatabaseCreate(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 146 | c := m.(*client.UpstashClient) 147 | 148 | var readRegions []string 149 | for _, v := range (data.Get("read_regions").(*schema.Set)).List() { 150 | if v != nil { 151 | readRegions = append(readRegions, v.(string)) 152 | } 153 | } 154 | 155 | database, err := CreateDatabase(c, CreateDatabaseRequest{ 156 | Region: data.Get("region").(string), 157 | DatabaseName: data.Get("database_name").(string), 158 | Eviction: data.Get("eviction").(bool), 159 | AutoUpgrade: data.Get("auto_scale").(bool), 160 | ProdPack: data.Get("prod_pack").(bool), 161 | Budget: data.Get("budget").(int), 162 | PrimaryRegion: data.Get("primary_region").(string), 163 | Tls: data.Get("tls").(bool), 164 | ReadRegions: readRegions, 165 | }) 166 | if err != nil { 167 | return diag.FromErr(err) 168 | } 169 | data.SetId("upstash-database-" + database.DatabaseId) 170 | data.Set("database_id", database.DatabaseId) 171 | 172 | var ipAllowList []string 173 | for _, v := range (data.Get("ip_allowlist").(*schema.Set)).List() { 174 | if v != nil { 175 | ipAllowList = append(ipAllowList, v.(string)) 176 | } 177 | } 178 | 179 | if len(ipAllowList) > 0 { 180 | err = UpdateDBIpAllowlist(c, database.DatabaseId, UpdateDBIpAllowlistRequest{ 181 | AllowedIps: ipAllowList, 182 | }) 183 | if err != nil { 184 | return diag.FromErr(err) 185 | } 186 | } 187 | 188 | return resourceDatabaseRead(ctx, data, m) 189 | } 190 | 191 | func resourceDatabaseDelete(ctx context.Context, data *schema.ResourceData, m interface{}) diag.Diagnostics { 192 | c := m.(*client.UpstashClient) 193 | databaseId := data.Get("database_id").(string) 194 | err := DeleteDatabase(c, databaseId) 195 | if err != nil { 196 | return diag.FromErr(err) 197 | } 198 | return nil 199 | } 200 | -------------------------------------------------------------------------------- /upstash/redis/database/resource.go: -------------------------------------------------------------------------------- 1 | package database 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" 7 | 8 | "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" 9 | ) 10 | 11 | func ResourceDatabase() *schema.Resource { 12 | return &schema.Resource{ 13 | CreateContext: resourceDatabaseCreate, 14 | ReadContext: resourceDatabaseRead, 15 | UpdateContext: resourceDatabaseUpdate, 16 | DeleteContext: resourceDatabaseDelete, 17 | Schema: map[string]*schema.Schema{ 18 | "database_id": { 19 | Type: schema.TypeString, 20 | Computed: true, 21 | Description: "Unique Database ID for created database", 22 | }, 23 | "database_name": { 24 | Type: schema.TypeString, 25 | Required: true, 26 | ForceNew: true, 27 | Description: "Name of the database", 28 | }, 29 | "region": { 30 | Type: schema.TypeString, 31 | Required: true, 32 | ForceNew: true, 33 | Description: "Region of the database. For global gcp regions, use `gcp-global`. For globals, check for primary_region and read_regions fields", 34 | }, 35 | "endpoint": { 36 | Type: schema.TypeString, 37 | Computed: true, 38 | Description: "Database URL for connection", 39 | }, 40 | "password": { 41 | Type: schema.TypeString, 42 | Computed: true, 43 | Sensitive: true, 44 | Description: "Password of the database", 45 | }, 46 | "consistent": { 47 | Type: schema.TypeBool, 48 | Optional: true, 49 | Default: false, 50 | Description: "When enabled, all writes are synchronously persisted to the disk.", 51 | Deprecated: "Consistent option is deprecated.", 52 | }, 53 | "multizone": { 54 | Type: schema.TypeBool, 55 | Optional: true, 56 | Default: false, 57 | Description: "When enabled, database becomes highly available and is deployed in multiple zones. (If changed to false from true, results in deletion and recreation of the resource)", 58 | Deprecated: "Multizone option is deprecated. It is enabled by default for paid databases.", 59 | }, 60 | "tls": { 61 | Type: schema.TypeBool, 62 | Optional: true, 63 | Default: false, 64 | Description: "When enabled, data is encrypted in transit. TLS is enabled by default for newly created databases and cannot be disabled.", 65 | }, 66 | "eviction": { 67 | Type: schema.TypeBool, 68 | Optional: true, 69 | Default: false, 70 | Description: "Enable eviction, to evict keys when your database reaches the max size", 71 | }, 72 | "auto_scale": { 73 | Type: schema.TypeBool, 74 | Optional: true, 75 | Default: false, 76 | Description: "Upgrade to higher plans automatically when it hits quotas", 77 | }, 78 | "budget": { 79 | Type: schema.TypeInt, 80 | Optional: true, 81 | Default: 20, 82 | Description: "Budget for the database (default $20). It is used to limit the cost of the database. If the budget is reached, the database will be throttled until the next month.", 83 | }, 84 | "prod_pack": { 85 | Type: schema.TypeBool, 86 | Optional: true, 87 | Default: false, 88 | Description: "Whether Prod Pack is enabled for the database.", 89 | }, 90 | "primary_region": { 91 | Type: schema.TypeString, 92 | Optional: true, 93 | ForceNew: true, 94 | Description: "Primary region for the database (Only works if region='global'. Can be one of [us-east-1, us-west-1, us-west-2, eu-central-1, eu-west-1, sa-east-1, ap-southeast-1, ap-southeast-2])", 95 | }, 96 | "read_regions": { 97 | Type: schema.TypeSet, 98 | Elem: &schema.Schema{ 99 | Type: schema.TypeString, 100 | }, 101 | Optional: true, 102 | Description: "Read regions for the database (Only works if region='global' and primary_region is set. Can be any combination of [us-east-1, us-west-1, us-west-2, eu-central-1, eu-west-1, sa-east-1, ap-southeast-1, ap-southeast-2], excluding the one given as primary.)", 103 | }, 104 | "ip_allowlist": { 105 | Type: schema.TypeSet, 106 | Elem: &schema.Schema{ 107 | Type: schema.TypeString, 108 | }, 109 | Optional: true, 110 | Description: "Ip CIDR allowlist for the database. If not set, all IPs are allowed to connect to the database.", 111 | }, 112 | "port": { 113 | Type: schema.TypeInt, 114 | Computed: true, 115 | Description: "Port of the endpoint", 116 | }, 117 | "rest_token": { 118 | Type: schema.TypeString, 119 | Computed: true, 120 | Sensitive: true, 121 | Description: "Rest Token for the database.", 122 | }, 123 | "read_only_rest_token": { 124 | Type: schema.TypeString, 125 | Computed: true, 126 | Sensitive: true, 127 | Description: "Rest Token for the database.", 128 | }, 129 | "creation_time": { 130 | Type: schema.TypeInt, 131 | Computed: true, 132 | Description: "Creation time of the database", 133 | }, 134 | "database_type": { 135 | Type: schema.TypeString, 136 | Computed: true, 137 | Description: "Type of the database", 138 | }, 139 | "state": { 140 | Type: schema.TypeString, 141 | Computed: true, 142 | Description: "State of the database", 143 | }, 144 | "user_email": { 145 | Type: schema.TypeString, 146 | Computed: true, 147 | Description: "User email for the database", 148 | }, 149 | "db_max_clients": { 150 | Type: schema.TypeInt, 151 | Computed: true, 152 | Description: "Max clients for the database", 153 | }, 154 | "db_max_request_size": { 155 | Type: schema.TypeInt, 156 | Computed: true, 157 | Description: "Max request size for the database", 158 | }, 159 | "db_disk_threshold": { 160 | Type: schema.TypeInt, 161 | Computed: true, 162 | Description: "Disk threshold for the database", 163 | }, 164 | "db_max_entry_size": { 165 | Type: schema.TypeInt, 166 | Computed: true, 167 | Description: "Max entry size for the database", 168 | }, 169 | "db_memory_threshold": { 170 | Type: schema.TypeInt, 171 | Computed: true, 172 | Description: "Memory threshold for the database", 173 | }, 174 | "db_daily_bandwidth_limit": { 175 | Type: schema.TypeInt, 176 | Computed: true, 177 | Description: "Daily bandwidth limit for the database", 178 | }, 179 | "db_max_commands_per_second": { 180 | Type: schema.TypeInt, 181 | Computed: true, 182 | Description: "Max commands per second for the database", 183 | }, 184 | }, 185 | 186 | Importer: &schema.ResourceImporter{ 187 | StateContext: schema.ImportStatePassthroughContext, 188 | }, 189 | 190 | CustomizeDiff: customdiff.All( 191 | customdiff.ForceNewIfChange("consistent", func(ctx context.Context, old, new, meta interface{}) bool { 192 | return old.(bool) && !new.(bool) 193 | }), 194 | customdiff.ForceNewIfChange("tls", func(ctx context.Context, old, new, meta interface{}) bool { 195 | return old.(bool) && !new.(bool) 196 | }), 197 | ), 198 | } 199 | } 200 | --------------------------------------------------------------------------------