Importer
Description
Importer allows resources to customize their behavior during the import process when using asoctl import. This extension is invoked when importing existing Azure resources into Kubernetes as ASO resources, giving resources the ability to skip import, modify the imported resource, or perform additional validation.
The interface is called during the import workflow, after retrieving the resource from Azure but before writing it to a file. This allows resources to filter out unwanted resources or adjust the imported representation.
Interface Definition
See the Importer interface definition in the source code.
Motivation
The Importer extension exists to handle cases where:
- System-managed resources: Resources that are created/managed by Azure and shouldn’t be user created
- Default values: Resources that only have default settings and don’t need to be managed
- Read-only resources: Resources that can’t be created or modified by users
- Filtering criteria: Resources that don’t meet certain criteria for management
- Import validation: Resources that need validation before allowing import
- Resource transformation: Adjusting the imported resource to fit Kubernetes conventions
Many Azure services automatically create child resources or configurations. These often shouldn’t be managed by the operator as they’re managed by Azure.
When to Use
Implement Importer when:
- ✅ System-managed resources should be excluded from import
- ✅ Default/empty configurations don’t need management
- ✅ Read-only resources can’t be managed via ASO
- ✅ Import should be conditional based on resource properties
- ✅ Imported resources need validation or transformation
- ✅ Certain resource states should prevent import
Do not use Importer when:
- ❌ All resources of the type should be imported
- ❌ The filtering logic applies to all resources (add to asoctl)
- ❌ You want to modify how resources are retrieved from Azure (that’s not import)
- ❌ You’re trying to fix generator issues (fix the generator)
Example: MySQL Configuration Import Filtering
See the full implementation in flexible_servers_configuration_extensions.go.
Key aspects of this implementation:
- Chain pattern: Calls
next()first to get the imported resource - Type checking: Safely handles being called on wrong resource type
- Multiple filters: Several conditions that trigger skip
- Clear reasons: Each skip includes explanation for user feedback
- Default behavior: Returns original result when no filters apply
Common Patterns
Pattern 1: Skip System-Managed Resources
func (ex *ResourceExtension) Import(
ctx context.Context,
rsrc genruntime.ImportableResource,
owner *genruntime.ResourceReference,
next extensions.ImporterFunc,
) (extensions.ImportResult, error) {
result, err := next(ctx, rsrc, owner)
if err != nil {
return extensions.ImportResult{}, err
}
resource := rsrc.(*myservice.MyResource)
// Skip resources managed by the system
if resource.Spec.ManagedBy != nil && *resource.Spec.ManagedBy == "System" {
return extensions.ImportSkipped("system-managed resources shouldn't be imported"), nil
}
return result, nil
}
Pattern 2: Transform Before Import
func (ex *ResourceExtension) Import(
ctx context.Context,
rsrc genruntime.ImportableResource,
owner *genruntime.ResourceReference,
next extensions.ImporterFunc,
) (extensions.ImportResult, error) {
resource := rsrc.(*myservice.MyResource)
// Modify the resource before importing
// For example, clear fields that shouldn't be managed
if resource.Spec.AutoGeneratedField != nil {
resource.Spec.AutoGeneratedField = nil
}
// Proceed with import of modified resource
return next(ctx, rsrc, owner)
}
Import Workflow
Understanding the import process:
- Resource discovery:
asoctl importqueries Azure for resources - Resource retrieval: Full resource details fetched from Azure
- Conversion: Azure representation converted to ASO format
- Importer invoked: Custom
Import()method called - Skip or continue: Based on result, resource is written to YAML or skipped
- User notification: Skipped resources reported to user with reasons
Skip vs. Error
It’s important to distinguish between skipping and errors:
-
Skip (
ImportSkipped): Resource should not be imported, but import continues- Used for: System resources, defaults, read-only items
- Effect: Resource excluded from output, reason logged
- User sees: “Skipped N resources” with reasons
-
Error (
return error): Import process failed- Used for: Validation failures, unexpected states, bugs
- Effect: Import may abort or continue based on error handling
- User sees: Error message, stack trace
Testing
When testing Importer extensions:
- Test successful import: Verify normal resources import correctly
- Test skip conditions: Cover all skip scenarios with reasons
- Test error cases: Verify proper error handling
- Test transformation: If modifying resources, verify changes
- Test type safety: Ensure handling of unexpected types
User Experience
When resources are skipped during import, users see output like:
$ asoctl import azure-resource myserver --output yaml
Imported 12 resources
Skipped 5 resources:
- myserver-config-1: system-defaults don't need to be imported
- myserver-config-2: readonly configuration can't be set
- myserver-config-3: default value is the same as the current value
...
Clear, informative skip reasons help users understand why certain resources weren’t imported.
Important Notes
- Call
next(): Allows default import logic to run - Provide clear reasons: Skip reasons are shown to users
- Be consistent: Similar resources should skip for similar reasons
- Don’t skip too broadly: Only skip resources that truly shouldn’t be managed
- Document skip logic: Comment why specific conditions trigger skips
- Test with real imports: Verify skips work in practice with
asoctl import
Related Tools
- asoctl import: The CLI tool that uses the Importer extension
- Resource specifications: Define what makes a resource importable
- Generator: Creates the base ImportableResource implementation