Skip to content

Commit 0372e59

Browse files
committed
Add support to discover tenancy level resources if the compartmentId is for a root compartment
1 parent d71d5ca commit 0372e59

File tree

3 files changed

+95
-27
lines changed

3 files changed

+95
-27
lines changed

oci/export_compartment.go

Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ var resourceNameCount map[string]int
4343
var resourcesMap map[string]*schema.Resource
4444
var datasourcesMap map[string]*schema.Resource
4545
var compartmentScopeServices []string
46+
var tenancyScopeServices []string
4647
var isMissingRequiredAttributes bool
4748
var exportConfigProvider oci_common.ConfigurationProvider
4849
var tfHclVersion TfHclVersion
@@ -59,6 +60,13 @@ func init() {
5960
idx++
6061
}
6162

63+
tenancyScopeServices = make([]string, len(tenancyResourceGraphs))
64+
idx = 0
65+
for mode := range tenancyResourceGraphs {
66+
tenancyScopeServices[idx] = mode
67+
idx++
68+
}
69+
6270
isMissingRequiredAttributes = false
6371
}
6472

@@ -155,15 +163,30 @@ func RunExportCommand(args *ExportCommandArgs) (error, Status) {
155163
}
156164
}
157165

158-
args.finalizeServices()
166+
/*
167+
We do not get customer tenancy ocid from configuration provider in case of Instance Principals auth
168+
Getting the tenancy ocid by repeated Get calls on parent for compartment
169+
*/
170+
var tenancyOcid string
171+
if args.CompartmentId != nil && *args.CompartmentId != "" {
172+
tenancyOcid, err = getTenancyOcidFromCompartment(clients.(*OracleClients), *args.CompartmentId)
173+
if err != nil {
174+
return err, StatusFail
175+
}
176+
} else {
177+
// If compartment ocid not provided in arguments, get it from configuration provider
159178

160-
tenancyOcid, exists := clients.(*OracleClients).configuration["tenancy_ocid"]
161-
if !exists {
162-
return fmt.Errorf("[ERROR] could not get a tenancy OCID during initialization"), StatusFail
179+
tenancyId, exists := clients.(*OracleClients).configuration["tenancy_ocid"]
180+
if !exists {
181+
return fmt.Errorf("[ERROR] could not get a tenancy OCID during initialization"), StatusFail
182+
}
183+
tenancyOcid = tenancyId
163184
}
164185

165186
ctx := createResourceDiscoveryContext(clients.(*OracleClients), args, tenancyOcid)
166187

188+
args.finalizeServices(ctx)
189+
167190
/*
168191
Setting retry timeout to a lower value for resource discovery
169192
This is done to handle the 404 and 500 errors in case
@@ -199,9 +222,16 @@ func convertStringSliceToSet(slice []string, omitEmptyStrings bool) map[string]b
199222
return result
200223
}
201224

202-
func (args *ExportCommandArgs) finalizeServices() {
225+
func (args *ExportCommandArgs) finalizeServices(ctx *resourceDiscoveryContext) {
203226
if len(args.Services) == 0 {
204227
args.Services = compartmentScopeServices
228+
229+
/*
230+
If compartmentId provided is not provided or is a root compartment then discover tenancy scope resources too
231+
*/
232+
if args.CompartmentId != nil && (*args.CompartmentId == "" || *args.CompartmentId == ctx.tenancyOcid) {
233+
args.Services = append(args.Services, tenancyScopeServices...)
234+
}
205235
}
206236

207237
// Dedupes possible repeating services from command line and sorts them
@@ -429,33 +459,37 @@ func getDiscoverResourceSteps(ctx *resourceDiscoveryContext) ([]resourceDiscover
429459
}
430460

431461
func getDiscoverResourceWithGraphSteps(ctx *resourceDiscoveryContext) ([]resourceDiscoveryStep, error) {
432-
result := []resourceDiscoveryStep{}
433462

434-
tenancyResource := &OCIResource{
435-
compartmentId: ctx.tenancyOcid,
436-
TerraformResource: TerraformResource{
437-
id: ctx.tenancyOcid,
438-
terraformClass: "oci_identity_tenancy",
439-
terraformName: "export",
440-
},
463+
if ctx.CompartmentId == nil || *ctx.CompartmentId == "" {
464+
*ctx.CompartmentId = ctx.tenancyOcid
441465
}
466+
result := []resourceDiscoveryStep{}
442467

443-
for _, mode := range ctx.Services {
444-
if resourceGraph, exists := tenancyResourceGraphs[mode]; exists {
445-
result = append(result, &resourceDiscoveryWithGraph{
446-
root: tenancyResource,
447-
resourceGraph: resourceGraph,
448-
resourceDiscoveryBaseStep: resourceDiscoveryBaseStep{name: mode, ctx: ctx},
449-
})
468+
// Discover tenancy scope resources only if compartmentId is tenancy ocid
469+
if *ctx.CompartmentId == ctx.tenancyOcid {
470+
tenancyResource := &OCIResource{
471+
compartmentId: ctx.tenancyOcid,
472+
TerraformResource: TerraformResource{
473+
id: ctx.tenancyOcid,
474+
terraformClass: "oci_identity_tenancy",
475+
terraformName: "export",
476+
},
477+
}
478+
479+
for _, mode := range ctx.Services {
480+
if resourceGraph, exists := tenancyResourceGraphs[mode]; exists {
481+
result = append(result, &resourceDiscoveryWithGraph{
482+
root: tenancyResource,
483+
resourceGraph: resourceGraph,
484+
resourceDiscoveryBaseStep: resourceDiscoveryBaseStep{name: mode, ctx: ctx},
485+
})
450486

451-
vars["tenancy_ocid"] = fmt.Sprintf("\"%s\"", ctx.tenancyOcid)
452-
referenceMap[ctx.tenancyOcid] = tfHclVersion.getVarHclString("tenancy_ocid")
487+
vars["tenancy_ocid"] = fmt.Sprintf("\"%s\"", ctx.tenancyOcid)
488+
referenceMap[ctx.tenancyOcid] = tfHclVersion.getVarHclString("tenancy_ocid")
489+
}
453490
}
454491
}
455492

456-
if ctx.CompartmentId == nil || *ctx.CompartmentId == "" {
457-
*ctx.CompartmentId = ctx.tenancyOcid
458-
}
459493
compartmentResource := &OCIResource{
460494
compartmentId: *ctx.CompartmentId,
461495
TerraformResource: TerraformResource{
@@ -1242,3 +1276,25 @@ func readEnvironmentVars(d *schema.ResourceData) error {
12421276
}
12431277
return nil
12441278
}
1279+
1280+
func getTenancyOcidFromCompartment(clients *OracleClients, compartmentId string) (string, error) {
1281+
1282+
for true {
1283+
response, err := clients.identityClient().GetCompartment(context.Background(), oci_identity.GetCompartmentRequest{
1284+
CompartmentId: &compartmentId,
1285+
RequestMetadata: oci_common.RequestMetadata{
1286+
RetryPolicy: getRetryPolicy(true, "identity"),
1287+
},
1288+
})
1289+
if err != nil {
1290+
return "", fmt.Errorf("[ERROR] could not get tenancy ocid from compartment ocid %v", err)
1291+
}
1292+
if response.CompartmentId == nil {
1293+
log.Printf("[INFO] root compartment found %v", compartmentId)
1294+
return *response.Id, nil
1295+
}
1296+
compartmentId = *response.CompartmentId
1297+
}
1298+
1299+
return "", fmt.Errorf("[ERROR] could not get tenancy ocid from compartment ocid")
1300+
}

oci/export_resource_helpers.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,10 @@ func getNotFoundChildren(parent string, resourceGraph *TerraformResourceGraph, c
155155
if exists {
156156
for _, child := range childResources {
157157
*children = append(*children, child.resourceClass)
158-
getNotFoundChildren(child.resourceClass, resourceGraph, children)
158+
// Avoid recursion if a resource can be nested within itself e.g. compartments
159+
if child.resourceClass != parent {
160+
getNotFoundChildren(child.resourceClass, resourceGraph, children)
161+
}
159162
}
160163
}
161164
}

website/docs/guides/resource_discovery.html.markdown

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,16 @@ The generated `.tf` files contain the Terraform configuration with the resources
132132
* 0.11
133133
* 0.12
134134

135-
> **Note**: The compartment export functionality currently supports discovery of the target compartment. The ability to discover resources in child compartments is not yet supported.
135+
| Arguments | Resources discovered |
136+
| ----------| -------------------- |
137+
| compartment_id = \<empty or tenancy ocid\> <br> services= \<empty\> or not specified | all tenancy and compartment scope resources <br> |
138+
| compartment_id = \<empty or tenancy ocid\> <br> services= \<comma separated list of services\> | tenancy and compartment scope resources for the services specified |
139+
| compartment_id = \<non-root compartment\> <br> services= \<empty\> or not specified | all compartment scope resources only |
140+
| compartment_id = \<non-root compartment\> services=\<comma separated list of services\> | compartment scope resources for the services specified<br>tenancy scope resources will not be discovered even if services with such resources are specified |
141+
142+
> **Notes**:
143+
* The compartment export functionality currently supports discovery of the target compartment. The ability to discover resources in child compartments is not yet supported.
144+
* If using Instance Principals, resources can not be discovered if compartment_id is not specified
136145

137146
### Exit status
138147

0 commit comments

Comments
 (0)