Skip to content

feat(exporter): add Cloud Foundry App resource export support#232

Merged
gergely-szabo-sap merged 14 commits intomainfrom
feat/export-apps
Apr 27, 2026
Merged

feat(exporter): add Cloud Foundry App resource export support#232
gergely-szabo-sap merged 14 commits intomainfrom
feat/export-apps

Conversation

@gergely-szabo-sap
Copy link
Copy Markdown
Contributor

Summary

This PR adds support for exporting Cloud Foundry applications to Crossplane App resources. It enables users to migrate
existing CF apps to Crossplane-managed infrastructure.

Changes

  • feat(exporter): adding App resource (8e47b3e)

    • Implement cmd/exporter/cf/app/ package with full App export functionality
    • app.go: Core export logic with org/space filtering and name pattern matching
    • convert.go: CF App manifest to Crossplane App CR conversion
    • manifest.go: CF API manifest fetching and parsing
    • secret.go: Docker credential secret generation
    • Register app export in cmd/exporter/main.go
  • test(exporter): add unit tests for convertAppResource helpers (32e611b)

    • TestConvertDockerField: Docker config conversion with/without credentials
    • TestConvertProcessesField: Process configuration conversion (nil, empty, single, multiple)
    • TestGenerateDockerCredentialSecret: Secret generation validation
  • docs(exporter): add documentation comments to app export package (6a413f1)

    • Package-level documentation
    • Function documentation for all exported and internal functions
  • chore(clifford): bumping xp-clifford dependency (80ee652)

    • Update github.com/SAP/xp-clifford to latest version

Technical Details

The App exporter:

  • Fetches apps from CF API filtered by org/space GUIDs
  • Supports regex pattern matching for app names
  • Converts CF app manifests to Crossplane App resources
  • Handles Docker lifecycle apps with credential secrets
  • Supports process configuration (web, worker, etc.)
  • Includes health check configuration conversion
  • Resolves space references when resolveReferences is enabled

Testing

  • Unit tests added for conversion helper functions
  • All tests pass: make reviewable

@gergely-szabo-sap gergely-szabo-sap marked this pull request as ready for review March 23, 2026 15:03
@gergely-szabo-sap gergely-szabo-sap self-assigned this Mar 23, 2026
Copy link
Copy Markdown
Contributor

@ikhandamirov ikhandamirov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Just a few remarks. Please feel free to overrule.

Comment thread cmd/exporter/cf/app/convert.go Outdated
},
},
ForProvider: v1alpha1.AppParameters{
Name: app.GetName(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct to sanitize the name? Or should it be the original one from CF?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CF name may not conform to the Kubernetes naming requirements. That's why it needs to be sanitized, IMO.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it is not a name of a Kubernetes resource, is it? Isn't it just a forProvider field unrelated to k8s?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're right, it is being fixed

appWithComment.AddComment(err.Error())
}
}
managedApp.Spec.ForProvider.NoRoute = appManifest.NoRoute
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appManifest could be nil, as getAppManifest returns nil, nil in some cases.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, this needs to be treated.

Comment thread cmd/exporter/cf/app/manifest.go Outdated
"context"
"log/slog"

// kyaml "sigs.k8s.io/yaml"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: is this comment needed / intentional? Are you sure you don't want to use this package?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, it's a leftover comment.

Comment thread cmd/exporter/cf/app/manifest.go Outdated
Comment on lines +17 to +29
// type docker struct {
// Image string `json:"image"`
// Username *string `json:"username,omitempty"`
// }

// type application struct {
// Name string `json:"name"`
// Docker *docker `json:"docker,omitempty"`
// }

// type manifest struct {
// Applications []application `json:"applications"`
// }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: is this comment needed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, it's a leftover comment.

Comment thread cmd/exporter/cf/app/convert.go Outdated
Comment on lines +71 to +80
Command: &process.Command,
DiskQuota: &process.DiskQuota,
Instances: process.Instances,
Memory: &process.Memory,
Timeout: &process.Timeout,
HealthCheckConfiguration: v1alpha1.HealthCheckConfiguration{
HealthCheckType: (*string)(&process.HealthCheckType),
HealthCheckHTTPEndpoint: &process.HealthCheckHTTPEndpoint,
HealthCheckInterval: &process.HealthCheckInterval,
HealthCheckInvocationTimeout: &process.HealthCheckInvocationTimeout,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  Command:   &process.Command,
  DiskQuota: &process.DiskQuota,                                                                                                                                                                                                        
  Memory:    &process.Memory,                                                                                                                                                                                                           
  Timeout:   &process.Timeout,                                                                                                                                                                                                          
  HealthCheckHTTPEndpoint:      &process.HealthCheckHTTPEndpoint,                                                                                                                                                                       
  HealthCheckInterval:          &process.HealthCheckInterval,                                                                                                                                                                           
  HealthCheckInvocationTimeout: &process.HealthCheckInvocationTimeout,

They will always be non-nil in the output even when the CF API returned no value (empty string, zero). This differs from the CRD field definitions which are Optional and pointer-typed precisely so they can be omitted. Downstream, the controller will see these as explicitly set and may send unnecessary update calls.

Comment thread cmd/exporter/cf/app/convert.go Outdated
Comment on lines +149 to +152
ReadinessHealthCheckType: &appManifest.ReadinessHealthCheckType,
ReadinessHealthCheckHTTPEndpoint: &appManifest.ReadinessHealthCheckHttpEndpoint,
ReadinessHealthCheckInterval: &appManifest.ReadinessHealthCheckInterval,
ReadinessHealthCheckInvocationTimeout: &appManifest.ReadinessHealthInvocationTimeout,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above. They will always be non-nil in the output even when the CF API returned no value (empty string, zero). This differs from the CRD field definitions which are Optional and pointer-typed precisely so they can be omitted. Downstream, the controller will see these as explicitly set and may send unnecessary update calls.

t.Errorf("expected comment to be added to secret")
}
},
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: would it make sense to test edge cases like empty secret or user name?

… documentation

Add convertProcessConfiguration function to handle individual process conversion
from CF manifest to Crossplane ProcessConfiguration. This extracts the process
conversion logic into a separate, testable function.

Changes:
- convert.go: Add convertProcessConfiguration() helper, refactor
  convertProcessesField() to use the new helper, add documentation comments
  to convertProcessConfiguration and convertReadinessHealthCheckConfiguration
- convert_test.go: Add TestConvertProcessConfiguration with test cases:
  * process_with_all_fields_set
  * process_with_only_required_fields
  * process_with_partial_fields
  * Also includes TestConvertReadinessHealthCheckConfiguration tests
- manifest.go: Clean up commented code

The new helper conditionally sets fields only when they have non-zero values,
using nil pointers for omitted fields.
Add test cases covering empty username, empty secret name, and both
empty to improve coverage of the docker credential secret generation.
Update version and vendorHash in config.nix.
Replace `app.GetName()` with `app.Name` in `convertAppResource`.
Modified-by: gergely-szabo-sap <gergely.szabo@sap.com>
@gergely-szabo-sap gergely-szabo-sap deployed to pr-e2e-approval April 27, 2026 15:42 — with GitHub Actions Active
@gergely-szabo-sap gergely-szabo-sap merged commit 31b654f into main Apr 27, 2026
14 checks passed
@gergely-szabo-sap gergely-szabo-sap deleted the feat/export-apps branch April 27, 2026 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Extend the CF export tool that it supports all resource types

2 participants