Skip to content

Commit b940e72

Browse files
author
Ravi Tandon
committed
Provide additional error information in the case of compartment lookup failure during compartment creation
1 parent bb34ed5 commit b940e72

File tree

3 files changed

+52
-33
lines changed

3 files changed

+52
-33
lines changed

oci/identity_compartment_resource.go

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package provider
55
import (
66
"context"
77
"fmt"
8+
"log"
89
"strconv"
910
"strings"
1011
"time"
@@ -175,9 +176,9 @@ func (s *CompartmentResourceCrud) Create() error {
175176
} else { // @next-break: remove
176177
// Prevent potentially inferring wrong TenancyOCID from InstancePrincipal
177178
if auth := s.Configuration["auth"]; strings.ToLower(auth) == strings.ToLower(authInstancePrincipalSetting) {
178-
return fmt.Errorf("compartment_id must be specified for this resource")
179+
return fmt.Errorf("compartment_id must be specified for this resource when using with auth as '%s'", authInstancePrincipalSetting)
179180
}
180-
// Maintain legacy contract of compartment_id defaulting to tenancy ocid if not specified
181+
// Maintain legacy contract of compartment_id defaulting to tenancy_ocid if not specified
181182
c := *s.Client.ConfigurationProvider()
182183
if c == nil {
183184
return fmt.Errorf("cannot access tenancyOCID")
@@ -217,43 +218,49 @@ func (s *CompartmentResourceCrud) Create() error {
217218
if err != nil {
218219
if response.RawResponse != nil && response.RawResponse.StatusCode == 409 {
219220

220-
// It was determined that not enabling delete should also preserve the implicit importing behavior
221-
if enableDelete, ok := s.D.GetOkExists("enable_delete"); !ok || !enableDelete.(bool) {
222-
223-
// React to name collisions by basically importing that pre-existing compartment into this plan.
224-
if strings.Contains(err.Error(), "already exists") ||
225-
strings.Contains(err.Error(), "Maximum number of compartment") {
226-
// List all compartments using the datasource to find that compartment with the matching name.
227-
// CompartmentsDataSourceCrud requires a compartment_id, so forward whatever value was used in
228-
// the create attempt above.
229-
s.D.Set("compartment_id", request.CompartmentId)
230-
dsCrud := &CompartmentsDataSourceCrud{s.D, s.Client, nil}
231-
if err := dsCrud.Get(); err != nil {
232-
return err
233-
}
221+
// Return an error if 'enable_delete' was explicitly set to 'true' in case of automatic import on conflict
222+
if enableDelete, ok := s.D.GetOkExists("enable_delete"); ok && enableDelete.(bool) {
223+
return fmt.Errorf(`%s
234224
235-
for _, compartment := range dsCrud.Res.Items {
236-
if *compartment.Name == *request.Name {
237-
s.Res = &compartment
238-
//Update with correct description
239-
s.D.SetId(s.ID())
240-
return s.Update()
241-
}
242-
}
225+
If you define a compartment resource in your configurations with
226+
the same name as an existing compartment with 'enable_delete' set to 'true',
227+
the compartment will no longer be automatically imported.
228+
If you intended to manage an existing compartment, use terraform import instead.`, err)
229+
}
230+
231+
// React to name collisions or conflict errors by importing pre-existing compartment into this plan if the name matches.
232+
if strings.Contains(err.Error(), "already exists") ||
233+
strings.Contains(err.Error(), "Maximum number of compartment") {
234+
// List all compartments using the datasource to find that compartment with the matching name.
235+
// CompartmentsDataSourceCrud requires a compartment_id, so forward whatever value was used in
236+
// the create attempt above.
237+
s.D.Set("compartment_id", request.CompartmentId)
238+
log.Println(fmt.Sprintf("[DEBUG] The specified compartment with name '%s' may already exist, listing compartments to lookup with name instead.",
239+
*request.Name))
240+
dsCrud := &CompartmentsDataSourceCrud{s.D, s.Client, nil}
241+
if err := dsCrud.Get(); err != nil {
242+
return err
243243
}
244244

245-
} else {
245+
for _, compartment := range dsCrud.Res.Items {
246+
if *compartment.Name == *request.Name {
247+
s.Res = &compartment
248+
//Update with correct description
249+
s.D.SetId(s.ID())
250+
return s.Update()
251+
}
252+
}
253+
// Return an error if the lookup failed, to provide user with information on which compartment id and name were used for lookup
246254
return fmt.Errorf(`%s
247255
248-
If you define a compartment resource in your configurations with
249-
the same name as an existing compartment, the compartment will no
250-
longer be transparently imported. If you intended to manage
251-
an existing compartment, use terraform import instead.`, err)
256+
failed to lookup the compartment with name: '%s' in compartment_id: '%s'.
257+
Verify your configuration if the correct 'compartment_id' and 'name' were specified.
258+
In most cases, the 'compartment_id' will be your 'tenancy_ocid' with the exception of nested compartments.
259+
Refer to the 'oci_identity_compartment' documentation for more information.`, err, *request.Name, *request.CompartmentId)
252260
}
253261
}
254262
return err
255263
}
256-
257264
s.Res = &response.Compartment
258265
return nil
259266
}

oci/identity_compartment_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package provider
55
import (
66
"context"
77
"fmt"
8+
"regexp"
89
"testing"
910
"time"
1011

@@ -187,6 +188,15 @@ func TestIdentityCompartmentResource_basic(t *testing.T) {
187188
resource.TestCheckResourceAttr(resourceName, "name", "Network"),
188189
),
189190
},
191+
// verify error on existing compartment name where automatic import fails due to enable_delete
192+
{
193+
Config: config + compartmentIdVariableStr + CompartmentResourceDependencies +
194+
generateResourceFromRepresentationMap("oci_identity_compartment", "test_compartment", Required, Create, compartmentRepresentation) +
195+
generateResourceFromRepresentationMap("oci_identity_compartment", "test_compartment2", Required, Create,
196+
representationCopyWithNewProperties(compartmentRepresentation, map[string]interface{}{
197+
"enable_delete": Representation{repType: Required, create: `true`}})),
198+
ExpectError: regexp.MustCompile("If you intended to manage an existing compartment, use terraform import instead."),
199+
},
190200
},
191201
})
192202
}

website/docs/r/identity_compartment.html.markdown

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ This resource provides the Compartment resource in Oracle Cloud Infrastructure I
1111

1212
Creates a new compartment in the specified compartment.
1313

14-
**Important:** Compartments cannot be deleted.
14+
**Important:** Unless `enable_delete` is explicitly set to true:
15+
* Terraform will not delete compartments on destroy, and
16+
* For backwards compatibility, an existing compartment with the same name will be automatically imported into the state. Properties of the existing compartment will be updated to what is defined in the new configuration. This can cause a problem if multiple Terraform configurations are using the same compartment, but, for example, specify a different compartment description.
1517

1618
Specify the parent compartment's OCID as the compartment ID in the request object. Remember that the tenancy
1719
is simply the root compartment. For information about OCIDs, see
@@ -46,12 +48,12 @@ resource "oci_identity_compartment" "test_compartment" {
4648

4749
The following arguments are supported:
4850

49-
* `compartment_id` - (Required) The OCID of the parent compartment containing the compartment.
51+
* `compartment_id` - (Required) The OCID of the parent compartment containing the compartment. In most cases, the 'compartment_id' will be the 'tenancy_ocid' with the exception of nested compartments.
5052
* `defined_tags` - (Optional) (Updatable) Defined tags for this resource. Each key is predefined and scoped to a namespace. For more information, see [Resource Tags](https://docs.cloud.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). Example: `{"Operations.CostCenter": "42"}`
5153
* `description` - (Required) (Updatable) The description you assign to the compartment during creation. Does not have to be unique, and it's changeable.
5254
* `freeform_tags` - (Optional) (Updatable) Free-form tags for this resource. Each tag is a simple key-value pair with no predefined name, type, or namespace. For more information, see [Resource Tags](https://docs.cloud.oracle.com/iaas/Content/General/Concepts/resourcetags.htm). Example: `{"Department": "Finance"}`
5355
* `name` - (Required) (Updatable) The name you assign to the compartment during creation. The name must be unique across all compartments in the parent compartment. Avoid entering confidential information.
54-
* `enable_delete` - (Optional) Defaults to false. If omitted or set to false the provider will implicitly import the compartment if there is a name collision, and will not actually delete the compartment on destroy or removal of the resource declaration. If set to true, the provider will throw an error on a name collision with another compartment, and will attempt to delete the compartment on destroy or removal of the resource declaration.
56+
* `enable_delete` - (Optional) Defaults to false. If omitted or set to false the provider will implicitly import the compartment if there is a name collision, and will not actually delete the compartment on destroy or removal of the resource declaration. If set to true, the provider will throw an error on a name collision with another compartment, and will attempt to delete the compartment on destroy or removal of the resource declaration.
5557

5658

5759
** IMPORTANT **

0 commit comments

Comments
 (0)