Skip to content

Commit f12fa4d

Browse files
mikebreyMonica Joshi
authored andcommitted
Added - Support for CMEK for Oracle NoSQL Hosted Environments
1 parent e71139c commit f12fa4d

13 files changed

+1020
-6
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
2+
// Licensed under the Mozilla Public License v2.0
3+
4+
// This example illustrates how to update a NoSQL configuration. Conceptually, a
5+
// configuration serves as a centralized repository for global parameters that
6+
// affect the NoSQL service. Currently, there is only one such parameter: a
7+
// customer-provided key for encrypting NoSQL data at rest.
8+
9+
// The Customer-Managed Encryption Keys (CMEK) feature is exclusively available
10+
// in private NoSQL environments dedicated to a single tenancy, where the CMEK
11+
// option has been enabled. Updating the configuration of the default, regional,
12+
// multi-tenancy NoSQL service is not supported. Therefore, this example focuses
13+
// on updating the configuration for a private NoSQL environment that supports
14+
// this operation.
15+
16+
// To specify the dedicated environment, set the environment variable
17+
// CLIENT_HOST_OVERRIDES=oci_nosql.NosqlClient=$ENDPOINT
18+
// Where $ENDPOINT is the endpoint of the dedicated NoSQL environment.
19+
// For example:
20+
// $ export CLIENT_HOST_OVERRIDES=oci_nosql.NosqlClient=https://acme-widgets.nosql.oci.oraclecloud.com
21+
22+
// The key must be stored in an OCI vault, and is referenced by its vault and
23+
// key OCIDs. Note that the configuration cannot be deleted. To revert to the
24+
// default encryption key, set the TF_VAR_vault_ocid and TF_VAR_key_ocid
25+
// environment variables to be empty, or assign the literal value of null
26+
// to kms_key.id and kms_key.kms_vault_id.
27+
28+
variable "tenancy_ocid" {}
29+
variable "user_ocid" {}
30+
variable "fingerprint" {}
31+
variable "private_key_path" {}
32+
variable "region" {}
33+
34+
variable "key_ocid" {}
35+
variable "vault_ocid" {}
36+
37+
provider "oci" {
38+
tenancy_ocid = var.tenancy_ocid
39+
user_ocid = var.user_ocid
40+
fingerprint = var.fingerprint
41+
private_key_path = var.private_key_path
42+
region = var.region
43+
}
44+
45+
resource "oci_nosql_configuration" "example_configuration" {
46+
compartment_id = var.tenancy_ocid
47+
environment = "HOSTED"
48+
kms_key {
49+
kms_vault_id = var.vault_ocid
50+
id = var.key_ocid
51+
}
52+
}
53+
54+
data "oci_nosql_configuration" "test_configurations" {
55+
compartment_id = var.tenancy_ocid
56+
}
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
2+
// Licensed under the Mozilla Public License v2.0
3+
4+
package integrationtest
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
10+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
11+
"github.com/hashicorp/terraform-plugin-testing/terraform"
12+
13+
"github.com/oracle/terraform-provider-oci/httpreplay"
14+
"github.com/oracle/terraform-provider-oci/internal/acctest"
15+
16+
"github.com/oracle/terraform-provider-oci/internal/utils"
17+
)
18+
19+
var (
20+
NosqlConfigurationRequiredOnlyResource = acctest.GenerateResourceFromRepresentationMap("oci_nosql_configuration", "test_configuration",
21+
acctest.Optional, acctest.Create, NosqlConfigurationRepresentation)
22+
23+
NosqlConfigurationResourceConfig = acctest.GenerateResourceFromRepresentationMap("oci_nosql_configuration", "test_configuration",
24+
acctest.Optional, acctest.Update, NosqlConfigurationRepresentation)
25+
26+
NosqlConfigurationDataResourceConfig = acctest.GenerateDataSourceFromRepresentationMap("oci_nosql_configuration", "test_configuration",
27+
acctest.Required, acctest.Create, NosqlConfigurationSingularDataSourceRepresentation)
28+
29+
UnassignKeyResourceConfig = acctest.GenerateResourceFromRepresentationMap("oci_nosql_configuration", "test_configuration",
30+
acctest.Required, acctest.Update, UnassignKeyRepresentation)
31+
32+
NosqlConfigurationSingularDataSourceRepresentation = map[string]interface{}{
33+
"compartment_id": acctest.Representation{RepType: acctest.Required, Create: `${var.compartment_id}`},
34+
}
35+
36+
NosqlConfigurationRepresentation = map[string]interface{}{
37+
"compartment_id": acctest.Representation{RepType: acctest.Required, Create: `${var.compartment_id}`, Update: `${var.compartment_id}`},
38+
"environment": acctest.Representation{RepType: acctest.Required, Create: `HOSTED`, Update: `HOSTED`},
39+
"is_opc_dry_run": acctest.Representation{RepType: acctest.Optional, Create: `false`, Update: `false`},
40+
"kms_key": acctest.RepresentationGroup{RepType: acctest.Optional, Group: NosqlConfigurationKmsKeyRepresentation},
41+
}
42+
43+
NosqlConfigurationKmsKeyRepresentation = map[string]interface{}{
44+
"id": acctest.Representation{RepType: acctest.Optional, Create: `${var.key_id}`, Update: `${var.key_id2}`},
45+
"kms_vault_id": acctest.Representation{RepType: acctest.Optional, Create: `${var.vault_id}`, Update: `${var.vault_id}`},
46+
}
47+
48+
UnassignKeyRepresentation = map[string]interface{}{
49+
"compartment_id": acctest.Representation{RepType: acctest.Required, Update: `${var.compartment_id}`},
50+
"environment": acctest.Representation{RepType: acctest.Required, Update: `HOSTED`},
51+
"kms_key": acctest.RepresentationGroup{RepType: acctest.Required, Group: UnassignKeyKmsKeyRepresentation},
52+
}
53+
54+
UnassignKeyKmsKeyRepresentation = map[string]interface{}{
55+
"id": acctest.Representation{RepType: acctest.Required, Update: nil},
56+
"kms_vault_id": acctest.Representation{RepType: acctest.Required, Update: nil},
57+
}
58+
)
59+
60+
// issue-routing-tag: nosql/default
61+
func TestNosqlConfigurationResource_basic(t *testing.T) {
62+
httpreplay.SetScenario("TestNosqlConfigurationResource_basic")
63+
defer httpreplay.SaveScenario()
64+
65+
config := acctest.ProviderTestConfig()
66+
67+
// Compartment_id is used to identify the tenancy.
68+
compartmentId := utils.GetEnvSettingWithBlankDefault("tenancy_ocid")
69+
compartmentIdVariableStr := fmt.Sprintf("variable \"compartment_id\" { default = \"%s\" }\n", compartmentId)
70+
71+
// Vault Id
72+
vaultId := utils.GetEnvSettingWithBlankDefault("vault_id")
73+
vaultIdVariableStr := fmt.Sprintf("variable \"vault_id\" { default = \"%s\" }\n", vaultId)
74+
75+
// Key Id
76+
keyId := utils.GetEnvSettingWithBlankDefault("key_id")
77+
keyIdVariableStr := fmt.Sprintf("variable \"key_id\" { default = \"%s\" }\n", keyId)
78+
79+
// Key Id for rotating key
80+
keyId2 := utils.GetEnvSettingWithBlankDefault("key_id2")
81+
keyId2VariableStr := fmt.Sprintf("variable \"key_id2\" { default = \"%s\" }\n", keyId2)
82+
83+
nosqlConfigurationResourceDependencies := keyIdVariableStr + keyId2VariableStr + vaultIdVariableStr
84+
85+
resourceName := "oci_nosql_configuration.test_configuration"
86+
87+
singularDatasourceName := "data.oci_nosql_configuration.test_configuration"
88+
89+
// Save TF content to Create resource with optional properties. This has to be exactly the same as the config part in the "create with optionals" step in the test.
90+
assignkey_config := config + compartmentIdVariableStr + nosqlConfigurationResourceDependencies + NosqlConfigurationRequiredOnlyResource
91+
updatekey_config := config + compartmentIdVariableStr + nosqlConfigurationResourceDependencies + NosqlConfigurationResourceConfig
92+
93+
get_configuration_config := config + compartmentIdVariableStr + NosqlConfigurationDataResourceConfig
94+
get_configuration_after_updatekey_config := get_configuration_config + nosqlConfigurationResourceDependencies + NosqlConfigurationResourceConfig
95+
get_configuration_after_unassignkey_config := get_configuration_config + UnassignKeyResourceConfig
96+
97+
acctest.SaveConfigContent(assignkey_config, "nosql", "configuration", t)
98+
99+
acctest.ResourceTest(
100+
t,
101+
nil,
102+
[]resource.TestStep{
103+
// verify Assign global encryption key
104+
{
105+
Config: assignkey_config,
106+
Check: acctest.ComposeAggregateTestCheckFuncWrapper(
107+
resource.TestCheckResourceAttr(resourceName, "compartment_id", compartmentId),
108+
resource.TestCheckResourceAttr(resourceName, "environment", "HOSTED"),
109+
resource.TestCheckResourceAttr(resourceName, "kms_key.#", "1"),
110+
resource.TestCheckResourceAttr(resourceName, "kms_key.0.id", keyId),
111+
resource.TestCheckResourceAttr(resourceName, "kms_key.0.kms_key_state", "ACTIVE"),
112+
resource.TestCheckResourceAttr(resourceName, "kms_key.0.kms_vault_id", vaultId),
113+
114+
func(s *terraform.State) (err error) {
115+
_, err = acctest.FromInstanceState(s, resourceName, "id")
116+
return err
117+
},
118+
),
119+
},
120+
121+
// verify Update (rotate) global encryption key
122+
{
123+
Config: updatekey_config,
124+
Check: acctest.ComposeAggregateTestCheckFuncWrapper(
125+
resource.TestCheckResourceAttr(resourceName, "compartment_id", compartmentId),
126+
resource.TestCheckResourceAttr(resourceName, "environment", "HOSTED"),
127+
resource.TestCheckResourceAttr(resourceName, "kms_key.#", "1"),
128+
resource.TestCheckResourceAttr(resourceName, "kms_key.0.id", keyId2),
129+
resource.TestCheckResourceAttr(resourceName, "kms_key.0.kms_key_state", "ACTIVE"),
130+
resource.TestCheckResourceAttr(resourceName, "kms_key.0.kms_vault_id", vaultId),
131+
132+
func(s *terraform.State) (err error) {
133+
_, err = acctest.FromInstanceState(s, resourceName, "id")
134+
return err
135+
},
136+
),
137+
},
138+
139+
// verify singular datasource
140+
{
141+
Config: get_configuration_after_updatekey_config,
142+
Check: acctest.ComposeAggregateTestCheckFuncWrapper(
143+
resource.TestCheckResourceAttr(singularDatasourceName, "compartment_id", compartmentId),
144+
resource.TestCheckResourceAttr(singularDatasourceName, "environment", "HOSTED"),
145+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.#", "1"),
146+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.0.id", keyId2),
147+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.0.kms_key_state", "ACTIVE"),
148+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.0.kms_vault_id", vaultId),
149+
resource.TestCheckResourceAttrSet(singularDatasourceName, "kms_key.0.time_created"),
150+
resource.TestCheckResourceAttrSet(singularDatasourceName, "kms_key.0.time_updated"),
151+
),
152+
},
153+
154+
// verify resource import
155+
{
156+
Config: updatekey_config,
157+
ImportState: true,
158+
ImportStateIdFunc: getConfigurationCompositeId(resourceName),
159+
ImportStateVerify: true,
160+
ImportStateVerifyIgnore: []string{"is_opc_dry_run"},
161+
ResourceName: resourceName,
162+
},
163+
164+
// verify key unassignment
165+
{
166+
Config: config + compartmentIdVariableStr + UnassignKeyResourceConfig,
167+
},
168+
169+
// verify singular datasource after unassign key
170+
{
171+
Config: get_configuration_after_unassignkey_config,
172+
Check: acctest.ComposeAggregateTestCheckFuncWrapper(
173+
resource.TestCheckResourceAttr(singularDatasourceName, "compartment_id", compartmentId),
174+
resource.TestCheckResourceAttr(singularDatasourceName, "environment", "HOSTED"),
175+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.#", "1"),
176+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.0.id", ""),
177+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.0.kms_vault_id", ""),
178+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.0.kms_key_state", "ACTIVE"),
179+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.0.time_created", ""),
180+
resource.TestCheckResourceAttr(singularDatasourceName, "kms_key.0.time_updated", ""),
181+
),
182+
},
183+
})
184+
}
185+
186+
// Gets the composite Id of the configuration resource
187+
func getConfigurationCompositeId(resourceName string) resource.ImportStateIdFunc {
188+
return func(s *terraform.State) (string, error) {
189+
rs, ok := s.RootModule().Resources[resourceName]
190+
if !ok {
191+
return "", fmt.Errorf("not found: %s", resourceName)
192+
}
193+
return fmt.Sprintf("configuration/compartmentId/%s", rs.Primary.Attributes["compartment_id"]), nil
194+
}
195+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
2+
// Licensed under the Mozilla Public License v2.0
3+
4+
package nosql
5+
6+
import (
7+
"context"
8+
"log"
9+
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
oci_nosql "github.com/oracle/oci-go-sdk/v65/nosql"
12+
13+
"github.com/oracle/terraform-provider-oci/internal/client"
14+
"github.com/oracle/terraform-provider-oci/internal/tfresource"
15+
)
16+
17+
func NosqlConfigurationDataSource() *schema.Resource {
18+
fieldMap := make(map[string]*schema.Schema)
19+
fieldMap["compartment_id"] = &schema.Schema{
20+
Type: schema.TypeString,
21+
Required: true,
22+
}
23+
return tfresource.GetSingularDataSourceItemSchema(NosqlConfigurationResource(), fieldMap, readSingularNosqlConfiguration)
24+
}
25+
26+
func readSingularNosqlConfiguration(d *schema.ResourceData, m interface{}) error {
27+
sync := &NosqlConfigurationDataSourceCrud{}
28+
sync.D = d
29+
sync.Client = m.(*client.OracleClients).NosqlClient()
30+
31+
return tfresource.ReadResource(sync)
32+
}
33+
34+
type NosqlConfigurationDataSourceCrud struct {
35+
D *schema.ResourceData
36+
Client *oci_nosql.NosqlClient
37+
Res *oci_nosql.GetConfigurationResponse
38+
}
39+
40+
func (s *NosqlConfigurationDataSourceCrud) VoidState() {
41+
s.D.SetId("")
42+
}
43+
44+
func (s *NosqlConfigurationDataSourceCrud) Get() error {
45+
request := oci_nosql.GetConfigurationRequest{}
46+
47+
if compartmentId, ok := s.D.GetOkExists("compartment_id"); ok {
48+
tmp := compartmentId.(string)
49+
request.CompartmentId = &tmp
50+
}
51+
52+
request.RequestMetadata.RetryPolicy = tfresource.GetRetryPolicy(false, "nosql")
53+
54+
response, err := s.Client.GetConfiguration(context.Background(), request)
55+
if err != nil {
56+
return err
57+
}
58+
59+
s.Res = &response
60+
return nil
61+
}
62+
63+
func (s *NosqlConfigurationDataSourceCrud) SetData() error {
64+
if s.Res == nil {
65+
return nil
66+
}
67+
68+
var resourceId string
69+
if compartmentId, ok := s.D.GetOkExists("compartment_id"); ok {
70+
tmp := compartmentId.(string)
71+
resourceId = GetConfigurationCompositeId(tmp)
72+
} else {
73+
resourceId = tfresource.GenerateDataSourceHashID("NosqlConfigurationDataSource-", NosqlConfigurationDataSource(), s.D)
74+
}
75+
76+
s.D.SetId(resourceId)
77+
switch v := (s.Res.Configuration).(type) {
78+
case oci_nosql.HostedConfiguration:
79+
s.D.Set("environment", "HOSTED")
80+
81+
if v.KmsKey != nil {
82+
s.D.Set("kms_key", []interface{}{KmsKeyToMap(v.KmsKey)})
83+
} else {
84+
s.D.Set("kms_key", nil)
85+
}
86+
case oci_nosql.MultiTenancyConfiguration:
87+
s.D.Set("environment", "MULTI_TENANCY")
88+
default:
89+
log.Printf("[WARN] Received 'environment' of unknown type %v", s.Res.Configuration)
90+
return nil
91+
}
92+
93+
return nil
94+
}

0 commit comments

Comments
 (0)